Сбор мусора струнных литералов

Я читаю о сборке мусора, и я получаю запутывающие результаты поиска, когда я ищу коллекции строковых литералов String.

Мне нужно уточнить следующие пункты:

  • Если строка во время компиляции определяется как литерал [например: String str = "java"], будет ли это сбор мусора?

  • Если используется метод intern [например: String str = new String("java").intern()], будет ли он собираться мусор? Также будет обрабатываться иначе, чем строковый литерал в точке 1.

  • В некоторых местах упоминается, что литералы будут собирать мусор только тогда, когда класс String будет выгружен? Имеет ли смысл, потому что я не думаю, что класс String когда-нибудь будет выгружен.

Ответ 1

Если строка во время компиляции определяется как литерал [например: String str = "java";], будет ли это сбор мусора?

Наверное, нет. Объекты кода будут содержать одну или несколько ссылок на объекты String, которые представляют литералы. До тех пор, пока объекты кода достижимы, объекты String будут.

Возможно, объекты кода становятся недоступными, но только если они динамически загружены... и их загрузчик классов уничтожен.

Если я использую метод intern (например: String str = new String("java").intern()), будет ли это сбор мусора?

Объект, возвращаемый вызовом intern, будет тем же самым объектом, который представляет строковый литерал "java". (Литерал "java" интернирован во время загрузки класса. Когда вы затем ставите новый объект String в фрагменте кода, он будет искать и возвращать ранее интернированную строку "java".)

Однако интернированные строки, которые не идентичны строковым литералам, могут быть собраны в мусор, как только они становятся недоступными. Пространство PermGen - это мусор, собранный на всех последних JVM HotSpot. (До Java 8... который полностью отбрасывает PermGen.)

Также он будет обрабатываться иначе, чем строковый литерал в точке 1.

Нет... потому что это тот же объект, что и строковый литерал.

И действительно, как только вы поймете, что происходит, ясно, что строковые литералы тоже не рассматриваются. Это просто применение правила "достижимости"...

В некоторых местах упоминается, что литералы будут собирать мусор только тогда, когда класс String будет выгружен? Это имеет смысл, потому что я не думаю, что класс String будет выгружен.

Вы правы. Это не имеет смысла. Источники, которые сказали, что неверны. (Было бы полезно, если бы вы разместили URL-адрес, чтобы мы могли прочитать, что они говорят для себя...)

Ответ 2

При нормальных обстоятельствах строковые литералы и классы распределяются в постоянное поколение JVM ( "PermGen" ) и обычно не собираются. Строки, которые интернированы (например, mystring.intern()), хранятся в пуле памяти, принадлежащем классу String в пермгене, и когда-то случай, когда агрессивное интернирование могло вызвать утечку пространства, потому что сам пул строк содержал ссылку на каждый string, даже если других ссылок не существует. По-видимому, это уже не так, по крайней мере, от JDK 1.6 (см., Например, здесь).

Для получения дополнительной информации о permgen, этот является достойным обзором темы. (Примечание: эта ссылка относится к блогу, связанному с продуктом. У меня нет связи с блогом, компанией или продуктом, но запись в блоге полезна и не имеет большого отношения к продукту. )

Ответ 3

  • Литеральная строка останется в памяти до тех пор, пока программа находится в памяти.
  • str будет собран мусор, но литерал, из которого он создан, не будет.
  • Это имеет смысл, так как класс строки выгружается, когда программа выгружается.

Ответ 4

intern() проверяет доступность объекта в пуле строк. Если объект/литерал доступен, ссылка будет возвращена. Если литерала нет в пуле, тогда объект загружается в области perm (пул строк), а затем ссылка на него будет возвращена. Мы должны разумно использовать метод intern().