Влияет ли назначение объектов на null в Java на сборку мусора? - PullRequest
80 голосов
/ 16 января 2009

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

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

Ответы [ 13 ]

61 голосов
/ 16 января 2009

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

Но, как и все: это зависит. 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;
}

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

11 голосов
/ 16 января 2009

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

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

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

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

10 голосов
/ 16 января 2009

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

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

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

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

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

8 голосов
/ 16 января 2009

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

Foo bar = new Foo();

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

bar = null ;

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

7 голосов
/ 16 января 2009

Это зависит.

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

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

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

6 голосов
/ 16 января 2009

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

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

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

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

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

5 голосов
/ 02 июня 2009
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 решено. Хорошей практикой всегда является установка неиспользуемой переменной равной нулю

4 голосов
/ 09 декабря 2012

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

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

2 голосов
/ 16 января 2009

Да.

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

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

1 голос
/ 16 января 2009

Я полагаю, что ОП относится к таким вещам:

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, когда память все равно не нужна, что на самом деле может привести к снижению производительности ЦП, так как это будет сборка GC раньше.

...