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

Я читаю о сборке мусора и получаю запутанные результаты поиска при поиске строковых литеральных сборок мусора.

Мне нужны разъяснения по следующим пунктам:

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

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

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

4 ответа

Решение

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. Буквенная строка останется в памяти, пока программа находится в памяти.
  2. str будет собирать мусор, но буквальный, из которого он создан, не будет.
  3. Это имеет смысл, поскольку строковый класс выгружается при выгрузке программы.

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

Другие вопросы по тегам