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


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

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

13 75

13 ответов:

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

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

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

например, этот код из 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;
}

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

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

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

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

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

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

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

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

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

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

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

Foo bar = new Foo();

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

bar = null ;

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

Это зависит.

вообще говоря короче, вы храните ссылки на ваши объекты, быстрее они будут собраны.

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

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

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

обычно установка ссылок на null, означает для читателя кода, что этот объект полностью завершен и больше не должен беспокоиться.

подобный эффект может быть достигнут с помощью дополнительного набор фигурных скобок

{
  int l;
  {
    String bigThing = ....;
    l = bigThing.length();
  }
  ---
}

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

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; на это. Это всегда хорошая практика, чтобы установить неиспользуемую переменную в null

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

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

да.

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

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

Я предполагаю, что ОП имеет в виду такие вещи, как это:

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

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

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

в этом случае разве виртуальная машина не пометит их для GC, как только они покинут область действия?

или, с другой точки зрения, явное задание элементов в null приведет к тому, что они получат GC'D до того, как они выйдут из области видимости? Если это так, виртуальная машина может тратить время на GC'ING объекта, когда память не нужна в любом случае, что на самом деле приведет к ухудшению производительности использования ЦП, потому что это будет ГК передоза еще раньше.

"зависит"

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

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

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

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

для этого нет жесткого и быстрого правила. Пройдя по указанному выше месту null-присваивает в ваш код и запустить Profiler, чтобы увидеть, если это помогает в любом случае. Скорее всего, вы не увидите пользы.

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

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

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

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

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

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

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

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