Назначает ли объекты null в сборку мусора Java?

Назначение ссылки на неиспользуемые объекты на null в Java улучшает процесс сбора мусора любым измеримым способом?

Мой опыт работы с Java (и С#) научил меня, что часто встречается интуитивно, чтобы попытаться перехитрить виртуальную машину или JIT-компилятор, но я видел, что сотрудники используют этот метод, и мне интересно, если это хорошо практика подобрать или одно из этих предрассудков программирования вуду?

Ответ 1

Как правило, нет.

Но, как и все: это зависит. GC в Java в эти дни ОЧЕНЬ хорош, и все должно быть очищено очень скоро после того, как оно больше не доступно. Это сразу же после выхода из метода для локальных переменных и когда экземпляр класса больше не ссылается на поля.

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

Например, этот код из ArrayList:

public E remove(int index) {
    RangeCheck(index);

    modCount++;
    E oldValue = (E) elementData[index];

    int numMoved = size - index - 1;
    if (numMoved > 0)
         System.arraycopy(elementData, index+1, elementData, index,
             numMoved);
    elementData[--size] = null; // Let gc do its work

    return oldValue;
}

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

И

void foo() {
   Object o = new Object();
   /// do stuff with o
}

и

void foo() {
   Object o = new Object();
   /// do stuff with o
   o = null;
}

Функционально эквивалентны.

Ответ 2

По моему опыту, чаще всего люди отменяют ссылки из паранойи, а не из-за необходимости. Вот краткое руководство:

  1. Если объект A ссылается на объект B и вам больше не нужна эта ссылка, а объект A не подходит для сборки мусора, вам следует явно обнулить поле. Нет необходимости обнулять поле, если окружающий объект все равно собирается мусором. Обнуление полей в методе dispose() почти всегда бесполезно.

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

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

Ответ 3

Хорошая статья сегодня кодирует ужас.

Работа GC заключается в поиске объектов, которые не имеют указателей на них, область их поиска - куча/стек и любые другие пространства, которые у них есть. Таким образом, если вы установите переменную в null, фактический объект теперь никем не указан, и, следовательно, может быть GC'd.

Но так как GC может не работать в этот момент, вы можете ничего не покупать. Но если ваш метод довольно длинный (с точки зрения времени выполнения), это может стоить того, так как вы увеличите свои шансы на сбор GC этого объекта.

Проблема также может быть сложна с оптимизацией кода, если вы никогда не используете переменную после того, как вы установите ее в null, было бы безопасно оптимизировать удаление строки, которая устанавливает значение в null (на одну инструкцию меньше для выполнения). Таким образом, вы можете не получить никакого улучшения.

Итак, в заключение, да, это может помочь, но это не будет детерминированным.

Ответ 4

По крайней мере, в java это вообще не программирование вуду. Когда вы создаете объект в java, используя что-то вроде

Foo bar = new Foo();

вы делаете две вещи: во-первых, вы создаете ссылку на объект, а во-вторых, вы создаете сам объект Foo. Пока эта ссылка или другая существует, конкретный объект не может быть gc'd. однако, когда вы назначаете null этой ссылке...

bar = null ;

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

Ответ 5

Это зависит.

Как правило, короче вы держите ссылки на свои объекты, быстрее их собирают.

Если ваш метод требует 2 секунды для выполнения, и вам больше не нужен объект после одной секунды выполнения метода, имеет смысл очистить любые ссылки на него. Если GC видит, что через одну секунду ваш объект все еще ссылается, в следующий раз он может проверить его через минуту или около того.

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

Ответ 6

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

Как правило, установка ссылок на ноль означает для ЧИТАТЕЛЯ кода, с которым этот объект полностью завершен, и больше не должен беспокоиться.

Аналогичный эффект может быть достигнут путем введения более узкой области действия путем установки дополнительного набора скобок

{
  int l;
  {  // <- here
    String bigThing = ....;
    l = bigThing.length();
  }  // <- and here
}

это позволяет собирать мусор сразу после выхода из вложенных скобок.

Ответ 7

public class JavaMemory {
    private final int dataSize = (int) (Runtime.getRuntime().maxMemory() * 0.6);

    public void f() {
        {
            byte[] data = new byte[dataSize];
            //data = null;
        }

        byte[] data2 = new byte[dataSize];
    }

    public static void main(String[] args) {

        JavaMemory jmp = new JavaMemory();
        jmp.f();

    }

}

Выше программы выбрасывается OutOfMemoryError. Если вы раскомментируете data = null;, решается OutOfMemoryError. Всегда рекомендуется установить неиспользуемую переменную в значение null

Ответ 8

Я работал над приложением для видеоконференций один раз и заметил огромную огромную разницу в производительности, когда я потратил время на нулевые ссылки, как только мне не понадобился этот объект. Это было в 2003-2004 годах, и я могу только представить, что с тех пор GC стала еще умнее. В моем случае у меня было сотни объектов, идущих и выходящих из сферы действия каждую секунду, поэтому я заметил ГК, когда он ногами периодически. Однако после того, как я сделал это для нулевых объектов, GC остановил приостановку моего приложения.

Так что это зависит от того, что вы делаете...

Ответ 9

Да.

Из "Прагматического программиста" с .292:

Установив ссылку на NULL, вы уменьшите количество указателей на объект на один... (что позволит сборщику мусора удалить его)

Ответ 10

Я предполагаю, что OP ссылается на такие вещи:

private void Blah()
{
    MyObj a;
    MyObj b;

    try {
        a = new MyObj();
        b = new MyObj;

        // do real work
    } finally {
        a = null;
        b = null;
    }
}

В этом случае, не будет ли VM отмечать их для GC, как только они покинут область видимости?

Или, с другой стороны, явное указание элементов на нуль, чтобы они могли получить GC'd до того, как они появятся, если они просто выйдут из области видимости? Если это так, VM может потратить время GC на объект, когда память не нужна в любом случае, что на самом деле приведет к худшему использованию ЦП процессора, потому что оно будет GC более ранним.

Ответ 11

"Это зависит от

Я не знаю о Java, но в .net(С#, VB.net...) обычно не требуется назначать нуль, когда вам больше не нужен объект.

Однако обратите внимание, что это "обычно не требуется".

Анализируя ваш код, компилятор .net делает хорошую оценку времени жизни переменной... точно указывать, когда объект больше не используется. Поэтому, если вы пишете obj = null, это может выглядеть так, как если бы obj все еще использовался... в этом случае встречный эффект для присваивания null.

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

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

Если это .net-код, который вы пытаетесь оптимизировать, то мой опыт заключается в том, что тщательный уход с методами Dispose и Finalize на самом деле более выгоден, чем беспокоиться о нулях.

Некоторые ссылки по теме:

http://blogs.msdn.com/csharpfaq/archive/2004/03/26/97229.aspx

http://weblogs.asp.net/pwilson/archive/2004/02/20/77422.aspx

Ответ 12

Даже если аннулирование справки было незначительно более эффективным, стоило бы уродство в том, чтобы перенести свой код на эти уродливые аннулирования? Они будут только беспорядочно и неясны код намерения, который их содержит.

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

Ответ 13

В будущем исполнении вашей программы значения некоторых элементов данных будут использоваться для вывода на компьютер внешнего вида, видимого вне программы. Другие могут использоваться или не использоваться, в зависимости от будущего (и невозможно предсказать) входы в программу. Возможно, другие члены данных не будут использоваться. Все ресурсы, включая память, выделенные для этих неиспользуемых данных, теряются впустую. Работа сборщика мусора (GC) заключается в том, чтобы устранить эту потерянную память. Было бы катастрофой для GC устранить то, что было необходимо, поэтому используемый алгоритм может быть консервативным, сохраняя более строгий минимум. Он может использовать эвристические оптимизации для улучшения своей скорости за счет сохранения некоторых предметов, которые на самом деле не нужны. Существует много потенциальных алгоритмов, которые может использовать GC. Поэтому возможно, что изменения, внесенные в вашу программу и не влияющие на правильность вашей программы, могут, тем не менее, влиять на работу GC, либо заставляя ее работать быстрее, чтобы выполнять ту же работу, или, скорее, идентифицировать неиспользуемые элементы. Таким образом, такое изменение, устанавливающее неприменимую ссылку на объект null, в теории не всегда является вуду.

Это вуду? Сообщается, что это часть кода библиотеки Java, который делает это. Авторы этого кода намного лучше, чем средние программисты, либо знают, либо сотрудничают с программистами, которые знают подробности реализаций сборщика мусора. Таким образом, это говорит о том, что иногда есть польза.