#java #memory-management #garbage-collection #string-pool
#java #управление памятью #сборка мусора #пул строк
Вопрос:
Итак, new String("abc");
создается объект в куче и литерал "abc"
в пуле строк в соответствии со многими ответами, которые я нашел. Поскольку было использовано ключевое слово new
, в пуле не должно быть ссылок на строковый литерал.
Означает ли это —
a. Литерал будет GC’ed при следующем запуске (при условии, что позже на литерал не было создано никаких других ссылок)?
b. Если (ответ на a) да, для JVM кажется довольно простым освободить литерал в пуле, как только объект создан, вместо ожидания GC. Почему это не сделано?
c. Если (ответ на a) «нет», какова причина того, что недоступный литерал не будет GC’ed?
Комментарии:
1. a. Да b. Удаление объектов — это работа GC. Я не знаю, но в моих ушах это звучит так, как будто это слишком усложнило бы ситуацию, если бы другие части JVM тоже начали удалять устаревшие объекты. Также был бы очень минимальный выигрыш, если таковой имеется.
2. @OleV.V. — На самом деле «a. No». Смотрите мой ответ.
3. Я верю тебе, @StephenC. Я не понял объяснения в вашем ответе, но не обращайте на это внимания.
Ответ №1:
Поскольку было использовано ключевое слово
new
, в пуле не должно быть ссылок на строковый литерал.
Это неверно. Вероятно, существует1 доступная ссылка на String
объект, который соответствует литералу. Насколько я помню, ссылка хранится в том же «фрейме», который содержит статические поля для класса. На практике эта ссылка будет оставаться доступной до тех пор, пока сборщик мусора не выгрузит заключающий класс. (Обычно этого никогда не происходит.)
Итак, ответы:
a. Литерал будет GC’ed при следующем запуске (при условии, что позже на литерал не было создано никаких других ссылок)?
Нет.
c. Если (ответ на a) «нет», какова причина того, что недоступный литерал не будет GC’ed?
String
Объект, соответствующий литералу, не является недоступным. Например, он должен быть достижимым, если существует какая-либо вероятность того, что new String("abc")
инструкция может быть выполнена снова.
Поскольку среде выполнения JVM сложно определить, что оператор (который был определен как доступный во время компиляции) не будет выполняться более одного раза во время выполнения, и поскольку при этом достигается небольшая выгода в производительности, среда выполнения предполагает, что все строковые литералы должны быть доступны в течение всего срока службы 2 классов Java, которые их определяют.
Наконец, как указывает @Holger, не имеет практического значения, когда объекты строкового литерала становятся недоступными. Мы знаем, что они будут присутствовать (в той или иной форме), если они необходимы. Это все, что действительно имеет значение.
1 — Фактическое поведение сильно зависит от реализации. В ранних JVM строковые объекты для литералов класса были с готовностью интернированы. Позже это изменилось на отложенное интернирование. Можно было бы даже повторно интернировать строковый объект каждый раз, когда используется строковый литерал, хотя в целом это было бы очень неэффективно. Затем нам нужно рассмотреть различные вещи, которые мог бы сделать оптимизатор. Например, можно заметить, что String
объект для литерала никогда не экранируется и используется таким образом, который фактически не требует интернирования. Или он мог заметить, что все выражение может быть оптимизировано.
2 — Я имею в виду классы. Вещи, которые соответствуют Class
объекту. Не экземпляры этих классов.
Комментарии:
1. Спасибо Стивену. На основе ссылки , объект считается мусором, когда к нему больше нельзя добраться ни по какому указателю в запущенной программе . В приведенном выше случае
new String("abc")
, как Java поддерживает указатель на созданный литерал?2. Он находится во внутренней структуре данных … этого вы не сможете увидеть, пока не начнете копаться в машинном коде, сгенерированном компилятором JIT. Но это, безусловно, есть, потому что
String
объект для литерала создается только один раз. (Я думаю, что ссылка хранится в том же фрейме, который содержит статические переменные класса.)
Ответ №2:
Поскольку new String(«abc»); является объектом и не интернирован, он будет собран мусором при следующем запуске GC.
-
Однако GC не будет немедленно запущен только для сбора этого строкового объекта из-за различных причин производительности и доступности пространства.
-
Использование System.gc(); также не гарантирует, что он будет запущен (это просто предложение для GC для запуска.)
GC выполняется по многим причинам, некоторые из которых похожи на приведенные ниже (также зависит от виртуальной машины)
Больше выделения памяти в определенном поколении не выполняется. Выделение кучи или наличие объектов, достигающих порогового значения и т.д.
Комментарии:
1. Имейте в виду, что в
String
работе участвуют дваnew String("abc")
объекта: строковый литерал"abc"
, который интернирован, иString
созданный черезnew
, который не интернирован. Оба имеют одинаковое содержимое.2. На самом деле вопрос заключается в том, будет ли литерал собран мусором. (Не объект, созданный
new
оператором.)