Подтвердить что ты не робот

Сбор мусора по локальной переменной

Я программист на С++, входящий в мир Java. И я не могу избавиться от плохого чувства, связанного с тем, чтобы позволить сборщику мусора Java делать мою очистку.

Как, например, будет ли этот код работать в Java?

public void myFunction() {
    myObject object = new myObject();
    object.doSomething();
}

Будет ли удаляться локальный объект переменной при выходе из myFunction()?

Должен ли я устанавливать объект до нуля до выхода, или он будет недоступен и будет удален GC? Или, в худшем случае, он будет течь, как в С++?

4b9b3361

Ответ 1

Это будет сбор мусора в какой-то момент после того, как он больше не используется. Я считаю, что в текущих реализациях Java он будет сохраняться до конца метода, тогда как сборщик мусора в .NET более агрессивен. (Я не знаю, есть ли какие-либо гарантии даже на Java. Обычно вам нужно, чтобы локальная переменная сохранялась за пределами ее последнего возможного чтения, когда вы отлаживаете.)

Но нет, вам не нужно устанавливать переменную в значение null, и это может ухудшить читаемость.

Маловероятно, что объект будет собирать мусор сразу после выхода метода; это до того момента, когда GC работает... и, конечно, если что-то еще держит ссылку на объект, в любом случае она может не иметь права на сборку мусора. Не забывайте, что значение переменной - это просто ссылка, а не сам объект. (Это может занять некоторое время, чтобы привыкнуть к С++.)

Ответ 2

Я столкнулся с этим кодом:

{
   final List myTooBigList = new ArrayList();
   ... overfill the list
}
somethingRunOutOfMemory();

somethingRunOutOfMemory(), потому что myTooBigList не был GCable, несмотря на то, что он больше не был в области.

Как и в C, локальные переменные расположены в стеке рядом с кадрами. Указатель стека резервирует столько места, сколько требуется для локальных переменных в области видимости. Локальная переменная блока становится GCable, когда стек повторно используется. Когда из области видимости указатель перемещается назад, как только это требуется новыми локальными переменными.

Они GCable после:

try { } catch : after exit by catch because catch reuses stack
for { } : after exit loop condition  because evaluation reuses stack
while { }: after exit loop condition because evaluation reuses stack
{ } followed by any local declaration that reuses stack

Они не GCable после:

try { } finally
try { } catch : after nothing caught
for { } : after break
while { } : after break
do { } while : after loop condition
if { }
{ } not followed by a local declaration

Если я хочу, чтобы local был GCable, я пишу:

{
   final List myTooBigList = new ArrayList();
   ... overfill the list
}
Object fake = null;
somethingDoesntRunOutOfMemory();

Аффектация подделки перемещает указатель стека назад и делает myTooBigList GCable. Удивительно, что (по крайней мере, в тестировании jvm) мы должны явно использовать стек. Было бы более ожидаемым, что локальные переменные будут GCable, как только выйдет из блока, но я думаю, что это компромисс с производительностью. Это усложнит байт-код.

ПРИМЕЧАНИЕ. Чтобы проверить, является ли переменная GCable, я запускаю GC, затем сравниваю значение WeakReference (my variable) с нулевым.

final WeakReference gctest;
{
   final List myTooBigList = new ArrayList();
   gctest = new WeakReference(myTooBigList);
   ... overfill the list
}
Object fake = null;
System.gc();
assert gctest.get() == null;

Ответ 3

Он выйдет за рамки. В Java, когда никто больше не указывает на объект, будет собираться мусор или, по крайней мере, он будет доступен для сбора мусора. Не нужно указывать здесь значение null. Иногда установка ссылки на объект на нуль необходима, если ваш объект будет жить в вашем приложении, но ссылка, которую он держит, должна быть собрана в мусор. В этом случае вы хотите освободить ссылку.