Что происходит с объектом при удалении ссылки на него?

Рейтинг: 2Ответов: 4Опубликовано: 08.03.2023

Есть три строки кода:

   String s = null; 
    s = "Hellow";
    s = null;
  1. Создали переменную s типа String, которая ни на что не ссылается (хранит пустую ссылку null).
  2. Создаем объект-строку Hellow, переменная s хранит ссылку на объект.
  3. Удаляем из переменной s ссылку на объект.

Вопрос: что происходит со строкой Hellow после удаления ссылки на неё? Остаётся ли она в памяти или удаляется вместе со ссылкой?

Ответы

▲ 3Принят

В Java за удаление неиспользуемых объектов отвечает сборщик мусора (анг. garbage collector). Он автоматически вызывается JVM в определённые моменты времени и удаляет те объекты, которые в данный момент в приложении не используются.

Однако в примере, приведённом вами, сборщик мусора не удалит строку, хоть вы и удалили ссылку на неё и более не используете. Дело в том, что строки в Java, создаваемые посредством кавычек, а не конструкторов, помещаются в так называемый пул строк (анг. string pool), который сборщиком мусора не затрагивается. Когда вы делаете так

s = "Hellow";

вы создаёте строку, которая будет помещена в пул строк. И даже если после этого s перестанет указывать на неё

s = null;

строка "Hellow" никогда не будет собрана сборщиком мусора, она останется в памяти, то есть, в пуле строк. Поэтому если далее сделать так

String s2 = "Hellow";
System.out.println("Hellow" == s2);

на экран будет выведено true. Потому что мы не создали новую строку, а указали на имеющуюся в пуле строк.

Однако если создавать строки посредством конструкторов

String s = new String("Hellow");

а затем затирать ссылки на них

s = null;

то в таком случае строки будут удаляться сборщиком мусора, как и любые обыкновенные объекты. И, например, такой код

String s2 = new String("Hellow");
System.out.println(new String("Hellow") == s2);

выведет на экран false, так как в обоих случаях создаются две независимые друг от друга строки "Hellow", находящиеся в разных местах памяти и при этом не находящиеся в пуле строк. Такие строки при затирании ссылок на них будут удаляться сборщиком мусора.

▲ 3

В данном сценарии строковый литерал "Hellow" определён в момент компиляции и соответственно будет размещён в пуле строк (string pool).

В старых версиях (Java 6 и раньше) пул строк являлся частью постоянной области памяти PermGen, которая не относилась к основной куче (Heap) и имела постоянный размер, который нельзя было увеличить.
Сборка мусора запускается только при условии, что существующая память исчерпана. Как правило, вероятность такого сценария для постоянной области памяти пренебрежимо мала -- нужно было бы или загружать множество классов или постоянно добавлять в пул новые строки при помощи String::intern. В худшем случае можно было бы добиться и OutOfMemoryError.

Начиная с Java 7 и выше пул строк размещается в куче (heap), для которой сборка мусора вызывается чаще (по сравнению с PermGen), при этом неиспользуемые строки удаляются из пула, освобождая память.
При необходимости размер кучи может увеличиваться, в том числе и превышая объём доступной физической памяти.

что происходит со строкой "Hellow" после удаления ссылки на неё? Остаётся ли она в памяти или удаляется вместе со ссылкой?

Строка останется в памяти (в данном случае, в пуле строк) до тех пор, пока не будет вызван сборщик мусора или не завершится программа.

▲ 0

Все вспоминают про то, что в java учетом используемых ссылок и подчисткой неиспользованной памяти занимается не программист, а сборщик мусора, но забывают, что и выделением памяти тоже занимается не программист. В приведенном фрагменте оптимизирующий компилятор сразу распознает паттерн присваивания без использования результата и не будет создавать строку и выполнять присваивание, так как результат от этого не изменится.

▲ -2

Она удалиться сборщиком мусора