В Java, когда объект не имеет живой ссылки, он имеет право на сбор мусора. Теперь в случае строки это не так, потому что строка войдет в пул строк, а JVM сохранит объект для повторного использования. Итак, это означает, что некогда созданная строка будет "никогда" не собирать мусор?
Когда строка будет мусором, собранным в java
Ответ 1
Теперь в случае строки это не так, потому что строка попадет в пул строк, а JVM сохранит объект для повторного использования. Значит, однажды созданная строка "никогда" не будет собираться мусором?
Во-первых, только строковые литералы (см. примечания) автоматически интернируются/добавляются в пул строк. String
объекты, созданные приложением во время выполнения, не интернируются... если только ваше приложение явно не вызывает String.intern()
.
Во-вторых, на самом деле правила для объектов сбора мусора в пуле строк такие же, как и для других объектов String
: на самом деле все объекты. Они будут собирать мусор, если они когда-нибудь станут недоступными.
На практике объекты String
, которые соответствуют строковым литералам, обычно не становятся кандидатами на сборку мусора. Это связано с тем, что в коде каждого метода, использующего литерал, имеется неявная ссылка на объект String
. Это означает, что String
достижимо до тех пор, пока метод может быть выполнен.
Тем не менее, это не всегда так. Если строковый литерал был определен в классе, который был динамически загружен (например, с помощью Class.forName(...)
), то можно договориться о том, чтобы класс был выгружен. Если это произойдет, тогда объект String
, соответствующий литералу, может быть недоступным и, в конечном счете, может быть GC-кодом.
См. также: Когда и как мусор классов собирается в Java?
Примечания:
Строковый литерал (JLS 3.10.5) - это строка, которая появляется в исходном коде Java; например,
"abc" // string literal new String(...) // not a string literal
Строка, полученная вычислением константного выражения (во время компиляции) (JLS 15.28), также может быть интернирована.
"abc" + 123 // 123 is a constant expression "abc" + Integer.valueOf(123) // Integer.valueOf(123) is also // a constant expression
Строго говоря, не все строковые литералы интернированы. Если литерал String появляется только в исходном коде как подвыражение константного выражения, этот литерал может не отображаться в файле ".class" ни в какой форме. Такой литерал не будет интернирован, потому что он не будет существовать во время выполнения.
Ответ 2
Вы правы; строки в пуле пользователя никогда не будут GC'd.
Однако большинство строк не интернированы.
Строковые литералы интернированы, а строки, переданные в String.intern()
, интернированы, но все остальные строки не интернированы и могут быть GC'd в обычном режиме.
Ответ 3
Строковые объекты, которые находятся в пуле строк, не будут собираться мусором. Другие объекты String будут собираться мусором, если у вас нет ссылки на него при выполнении вашей программы.
Вы можете спросить, какие строковые объекты идут в пул строк. Объектами в пуле строк являются:
Литералы времени компиляции (например,
String s1 = "123";
)Объекты Interned String во время выполнения (например,
String s2 = new String("test").intern();
)
И s1
, и s2
ссылаются на строковый объект в пуле строк.
Любые объекты, которые создаются во время выполнения и не являются внутренними, будут действовать как обычный объект и хранятся в динамической памяти. Эти объекты можно собирать мусором.
Примером этого может быть: String s3 = s1 + s2;
Здесь s3
ссылается на строковый объект, который находится в памяти кучи вместе с другими объектами (не в пуле строк).