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

вынужден добавитьmyLocalVar = null; заявление в предложение наконец перед выходом из метода. Причина в том, чтобы помочь GC. Мне сказали, что я получу SMS-сообщения ночью, когда сервер в следующий раз выйдет из строя, поэтому я лучше сделал это :-).

Я думаю, что это бессмысленно, так как myLocalVar находится в области действия метода и будет «потерян» при выходе из метода. Дополнительный обнуление просто загрязняет код, но безвреден.

Мой вопрос: откуда взялся этот миф о помощи GC? (Меня называли «книгами памяти на Java»). Знаете ли вы какую-нибудь статью «авторитетов», которая объясняет это более подробно? Есть ли вероятность, что это не миф, но действительно как-то помогает? Если да, то как? Может ли обнуление локальных переменных причинить какой-либо вред?

Чтобы уточнить, метод выглядит так:

void method() {
  MyClass myLocalVar = null;
  try {
    myLocalVar = get reference to object;
    ... do more here ...
  } finally {
    if (myLocalVar != null) {
      myLocalVar.close(); // it is resource which we should close
    }

    myLocalVar = null; // THIS IS THE LINE I AM TALKING ABOUT
  }
}

Ответы на вопрос(15)

но, насколько я помню, переменная является не чем иным, как ссылкой из текущего стекового фрейма, и пока эта ссылка не будет удалена, объект не может быть собран мусором. Теперь, но явно установив его в null, вы убедились, что ссылка исчезла. Если вы этого не сделаете, вы в основном позволяете ВМ решать, когда очищается эта ссылка, что может произойти или не произойти при выходе из области (в отличие от C ++, если объект находится в стеке и ДОЛЖЕН быть уничтожен). Это может быть, когда кадр стека перезаписывается следующим. Я не уверен, есть ли виртуальная машина, которая делает это.

Короткий ответ, однако, это не нужно, метка и развертка получат его в конце концов. Это в лучшем случае вопрос времени.

 Outlaw Programmer23 янв. 2009 г., 18:17
Объект находится в куче, но ссылка на него находится в стеке. Как только функция возвращается, ссылка удаляется, и объект больше не имеет допустимых ссылок. Это бесплатно быть GCed в любое время после этого. Нет необходимости «проверять», что ссылка исчезла, она ВСЕГДА исчезла.
 falstro23 янв. 2009 г., 18:15
теоретически вы, конечно, правы, как это на самом деле реализовано, это отдельная история.
 falstro23 янв. 2009 г., 18:28
Я никогда не говорил, что есть необходимость убедиться, вопрос был в том, имеет ли это значение, и я сказал, что это зависит от того, как реализация виртуальной машины обрабатывает ссылки из стековых фреймов. Это может не сделать (хотя это, безусловно, наиболее привлекательно), когда вы покидаете область видимости.
 kdgregory23 янв. 2009 г., 18:48
Согласно JLS и JVMSpec, виртуальная машина даже не должна собирать мусор ... но они делают. И хотя возможно, что какая-то реализация рассмотрит каждое возможное место в памяти (даже неиспользуемое) и решит, что может указывать на объект, это не имеет никакого смысла.
 Peter Štibraný23 янв. 2009 г., 18:13
Я считаю, что даже если стек не был перезаписан, он все равно не будет считаться ссылкой на объект, так как эта часть стека не используется.

который восходит к тому времени, когда впервые появилась Java, и ребята из C ++ не доверяли gc.

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

 Wim Coenen23 янв. 2009 г., 18:13
Это тоже не очень ясно написано. Некоторые люди на самом деле принимают идею, что им действительно следует закрыть, утилизировать и обнулить ресурсы. Пример:stackoverflow.com/questions/452327/...
 Outlaw Programmer23 янв. 2009 г., 18:15
-1 от меня, потому что я не думаю, что сообщение в блоге вообще «здорово».
 Jon Skeet23 янв. 2009 г., 18:11
Некоторые из этого поста в порядке. Другие части опасны. Относительно вызова Dispose как «оптимизации» вредно, ИМО. Прочитайте комментарии.
 Matt Briggs23 янв. 2009 г., 18:22
от «великого» до «довольно забавного», потому что именно поэтому я и подумал, что это здорово. Джон прав насчет однозначной вещи
 Peter Štibraný23 янв. 2009 г., 18:08
Отличный титул "Умри, Соска Свинья!" :-) Спасибо за указание на это.

когда было полезно установить переменную в нуль:

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

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

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

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

которая в любом случае немедленно выйдет из области видимости, не нужно и не имеет никакого значения для GC. Все, что он делает, это загромождает код. ВЭффективное Java, 2-е изданиеАвтор рекомендует против ненужного обнуления локальных переменных. См. Эффективная Java, 2-е издание, пункт 6: устранение устаревших ссылок на объекты для полной записи.

Вы также можете увидеть это в статьеСоздание и уничтожение объектов Java, в ИнформИТ. Читатьвся статья чтобы найти место, где Джошуа Блох соглашается с тобой.

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

РЕДАКТИРОВАТЬ: Добавить ссылку на Effective Java 2nd Edition на веб-сайте Sun

 Peter Štibraný24 янв. 2009 г., 00:35
Спасибо за ссылки, особенно. сообщить выдержки из EJ 2-е изд.

то обнуление объектов, на которые он ссылается, позволит их собирать.

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

Когда вы думаете о выделении и освобождении объектов, обратите внимание на вещи, которые обрабатывает «Система»: активные потоки, окна, которые не были утилизированы () d, и еще одну или две вещи, но я не могу вспомнить правильно в настоящее время.

Каждый объект в вашей системе «висит» от этих точек монтирования в гигантском перевернутом дереве. Если вы отрежете какую-либо ветку от этих «корней», вся ветка упадет на землю и будет собрана газонокосилкой для сбора мусора.

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

(кстати, эти обрезки довольно эффективны, даже более бесплатны, чем C ++, поскольку они не требуют прикосновения к каждому объекту при его освобождении)

имости, вы можете дать подсказку JVM и установить ссылку NULL.

public void foobar()
{
    List<SomeObject> dataList = new ArrayList<SomeObject>();

    // heavy computation here where objects are added to dataList 
    // and the list grows, maybe you will sort the list and
    // you just need the first element... 

    SomeObject smallest = dataList.get(0);

    // more heavy computation will follow, where dataList is never used again
    // so give the JVM a hint to drop it on its on discretion
    dataList = null;

    // ok, do your stuff other heavy stuff here... maybe you even need the 
    // memory that was occupied by dataList before... 

    // end of game and the JVM will take care of everything, no hints needed
}

Но это не имеет смысла перед возвратом, потому что это делается JVM автоматически. Так что я согласен со всеми сообщениями раньше.

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

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

Другие люди помещают локальные переменные в переменную экземпляра (например, передавая ее функции), а затем думают, что обнуление локальной переменной каким-то образом устраняет переменную, что, конечно, не соответствует действительности.

Наконец, есть люди, которые чрезмерно работают с GC и думают, что он сделает для них функциональное отключение (например, закроет соединения, когда переменная удалена), что, конечно, не так. Я думаю, что источником этой строки является «Я действительно покончил с этим, но я не уверен, как это обеспечить».

Так что да, вы правы, что это излишне.

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

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

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

SomeResult SomeFunction(SomeClass param) {
    TempData big = new TempData(param);
    IntermediateResult intermediate = big.GetIntermediateResult();
    big = null; // allow GC to reclaim the memory before returning from the function
    intermediate.FurtherProcessing();
    return intermediate.EvenMoreProcessing();
}
 zedoo28 сент. 2013 г., 14:06
Спасибо за этот ответ.
Решение Вопроса

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

Тем не менее, в документе упоминается очень старая версия Java. Как уже упоминалось вэтот вопрос (которая также содержит подробное описание проблемы, описанной в статье), это больше не влияет на текущие реализации JVM.

 OscarRyz24 февр. 2009 г., 21:18
Так? какой был ответ? ... (не заставляй меня читать): P
 Peter Štibraný02 февр. 2009 г., 19:15
Спасибо! Это объясняет, откуда происходит этот миф.
 Peter Štibraný24 февр. 2009 г., 21:33
В моем первоначальном вопросе это не помогает. Но см. Также мой ответ ниже (stackoverflow.com/questions/473685#583387), действительно есть случай, когда это может помочь.
 Roland Illig19 авг. 2014 г., 10:07
Ссылка на производительность платформы Java не работает.

бычно переменных экземпляра или класса). Но обнулитьместный Переменная непосредственно перед концом метода абсолютно ничего не делает.

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

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

обнуление в этом случае совершенно бессмысленно.

Вернемся к JDK1.3. У меня действительно был случай с очень большим графом объектов, который также содержал множество циклических ссылок в графе. Удаление некоторых ссылок действительно заметно улучшило время GC.

Я не уверен, применимо ли это к современной виртуальной машине. Сборщики мусора становятся все умнее.

 Darron23 янв. 2009 г., 22:40
У меня тоже была такая ситуация. В моем случае это была очень длинная цепочка предметов. Связанный список, который вырос из хвоста и сжался от головы. Очень быстро. Один GC не мог идти в ногу до тех пор, пока мы не обнулили ссылки, исходящие из головы. Это была Java 1.3
 Tom Hawtin - tackline23 янв. 2009 г., 18:17
Старые JMVs тоже этого не делали.
 krosenvold23 янв. 2009 г., 18:33
Я не знаю, почему у меня были улучшения, но я предполагаю, что это действительно означало меньше работы для сборщика мусора. Я не претендую на утечку памяти, просто улучшил время GC.
 Steve B.23 янв. 2009 г., 18:16
Для сборщика мусора, который использует подсчет ссылок, возможно получить утечку памяти с 2 объектами, которые (циклически) ссылаются друг на друга, поскольку у каждого по-прежнему есть существующая ссылка, и GC не поймет, что эти ссылки сами по себе относятся к объектам GCable , Современная JVM не делает этого
 Eddie23 янв. 2009 г., 21:26
Если у вас большой граф объектов и вы освобождаете объекты из этого графа, явное обнуление ссылок на освобождаемые объекты позволяет GC восстанавливать элементы, и это приводит к уменьшению количества «живых» объектов. Оба могут помочь ускорить сборщик мусора.

крайних случаях. Это не относится к ситуации в оригинальном вопросе, но в любом случае является образовательным ... Давайте рассмотрим эту программу:

public class Main {
    public static void main(String[] args) {
       {
           Main local = new Main();

           // inner = null;
       }

       while (true) {
           // long running method
       }
    }
}

Еслиinner = null; закомментировано, объект вlocal переменная не может быть собрана мусором во время цикла while. Причина в том, что виртуальная машина Java не знает о таких областях, как эта. Все это имеет:

D:\workspaces\workspace-3.4\test\src>javap -verbose -c Main
public class Main extends java.lang.Object
  minor version: 0
  major version: 50
  Constant pool:
const #1 = Method       #4.#11; //  java/lang/Object."<init>":()V
const #2 = class        #12;    //  Main
const #3 = Method       #2.#11; //  Main."<init>":()V
const #4 = class        #13;    //  java/lang/Object
const #5 = Asciz        <init>;
const #6 = Asciz        ()V;
const #7 = Asciz        Code;
const #8 = Asciz        main;
const #9 = Asciz        ([Ljava/lang/String;)V;
const #10 = Asciz       StackMapTable;
const #11 = NameAndType #5:#6;//  "<init>":()V
const #12 = Asciz       Main;
const #13 = Asciz       java/lang/Object;

{
public Main();
  Code:
   Stack=1, Locals=1, Args_size=1
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   Stack=2, Locals=2, Args_size=1
   0:   new     #2; //class Main
   3:   dup
   4:   invokespecial   #3; //Method "<init>":()V
   7:   astore_1
   8:   goto    8
  StackMapTable: number_of_entries = 1
   frame_type = 8 /* same */

}

Нет информации о области действия локальной переменной. Таким образом, с точки зрения JVM, вышеуказанная программа эквивалентна:

public class Main
{

    public Main() { }

    public static void main(String args[])
    {
        Main main1 = new Main();
        do
            ;
        while(true);
    }
}

(Генерируется декомпилятором JAD)

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

Это было вдохновлено комментарием отЗденек Троничек в списке рассылки java-cz (на чешском языке, извините)

 Peter Štibraný25 февр. 2009 г., 21:07
Я использовал Java 1.6.0_12 от Sun. Спасибо за указание, что д / а. Я вижу, что это то же самое, что я уже принял для этого вопроса ;-) (ваш ответ ... позор мне, я должен был прочитать его более тщательно в первый раз)
 Peter Štibraný25 февр. 2009 г., 07:27
С другой стороны, JVM, вероятно, может обнаружить, что локальная переменная не используется после инструкции 7, и оптимизировать ее.
 Bill Michell25 февр. 2009 г., 11:02
Какой компилятор / JVM вы использовали для этого? Видетьstackoverflow.com/questions/271613/... за экспериментальные доказательства того, что последние JVM могут собирать такие переменные внутри области видимости после того, как они выпадают из области видимости.

Ваш ответ на вопрос