2013-08-02 7 views
13

Я недавно изучал освобождение памяти, занимаемой объектами Java. Выполняя это, я запутался в том, как объекты копируются (неглубоко/глубоко) на Java и как избежать случайного удаления/уничтожения объектов, пока они все еще используются.очистка или установка null для объектов в java

Рассмотрим следующие сценарии:

  1. пропускании ArrayList<Object> в качестве аргумента метода.
  2. передается ArrayList<Object> классу runnable для обработки потоком.
  3. помещение ArrayList<Object> в HashMap.

Теперь, в этом случае, если я звоню list = null; или list.clear();, что происходит с объектами? В этом случае объекты теряются, и в каких случаях только ссылка имеет значение null?

Я предполагаю, что это связано с мелким и глубоким копированием объектов, но в каких случаях происходит мелкое копирование, и в этом случае происходит глубокая копия на Java?

+1

Я всегда находил один из наиболее привлекательных аспектов Java сборщик мусора ... –

ответ

36

Во-первых, вы никогда не устанавливаете объект на нуль. Эта концепция не имеет смысла. Вы можете присвоить значение null переменной , но вам нужно очень тщательно различать понятия «переменная» и «объект». Как только вы это сделаете, ваш вопрос будет отвечать самим образом:

Теперь с точки зрения «мелкой копии» и «глубокой копии» - здесь, вероятно, стоит избегать термина «мелкая копия», так как обычно мелкая копия включает в себя создание новый объект, но просто копирование полей существующего объекта напрямую. Глубокая копия возьмет копию объектов, на которые ссылаются эти поля (для полей ссылочного типа). Простое назначение так:

ArrayList<String> list1 = new ArrayList<String>(); 
ArrayList<String> list2 = list1; 

... не делает либо неполную копию или глубокой копии в этом смысле. Он просто копирует ссылку. После вышеописанного кода list1 и list2 являются независимыми переменными - в действительности они имеют одинаковые значения (ссылки) на данный момент. Мы могли бы изменить значение одного из них, и это не будет влиять на других:

list1 = null; 
System.out.println(list2.size()); // Just prints 0 

Теперь, если вместо изменения переменных, мы делаем изменения в объект, значения переменных относятся к , что изменения будут видны через другой переменной тоже:

list2.add("Foo"); 
System.out.println(list1.get(0)); // Prints Foo 

Итак, вернемся к первоначальному вопросу - вы никогда не храните реальные объекты в карте, список, массив и т.д. вы только когда-либо хранить ссылки.Объект может быть собран только при сборке мусора, если нет никакого способа «живого» кода, достигающего этого объекта. Так что в этом случае:

List<String> list = new ArrayList<String>(); 
Map<String, List<String>> map = new HashMap<String, List<String>>(); 
map.put("Foo", list); 
list = null; 

... ArrayList объект до сих пор не может быть мусора, потому что Map есть запись, которая относится к нему.

+0

thnks для очистки это не имеет ничего общего с мелким или глубоким копированием! – anzaan

1

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

Object myAwesomeObject = new Object(); 
List<Object> myList = new ArrayList<Object>(); 

myList.add(myAwesomeObject); 

myList = null; // Your object hasn't been claimed by the GC just yet, your variable "myAwesomeObject" is still refering to it 

myAwesomeObject = null; // done, now your object is eligible for garbage collection. 

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

+0

Вы забыли: 'myList.add (myAwesomeObject); ':))) – alfasin

+0

DUH !!! спасибо @alfasin – morgano

1

Если вы поместите список в хэш-карту, хеш-карта теперь содержит ссылку на список.

Если вы передадите список в качестве аргумента методу, метод будет иметь ссылку на него в течение всего метода.

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

Во всех этих случаях, если вы установили list = null, ссылки будут сохранены, но они исчезнут после исчезновения этих ссылок.

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

1

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

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

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

public class A{ 

    private List<Integer> list = new ArrayList<Integer>(); 
    public static void main(String[] args) { 
     A a = new A(); 
     B b = new B(); 

     b.method(a.list); 

     System.out.println(a.list.size()); //Will print 0 and not throw NullPointerException 
    } 

} 

class B{ 
    public void method(List<Integer> list){ 
     list = null; 
     //just this reference is set to null and not the original one 
     //so list of A will not be GCed 
    } 
} 
1

Если вы сдали ArrayList на метод, то список = нуль не будет иметь никакого эффекта, если есть живая ссылка на список где-то, например, в коде вызова. Если вы вызываете list.clear() в любом месте кода, ссылки на объекты из этого списка будут нулевыми. Передача ссылки на метод не является мелким копированием, она передает ссылку по значению

0

Я недавно изучал освобождение памяти, занимаемой объектами Java.

Кусок советов.

Обычно это Плохая идея, чтобы подумать об этом. И, как правило, худшей идеей является попытка «помочь». В 99,8% случаев сборщик мусора Java способен сделать лучшую работу по сбору мусора, если вы на самом деле просто позволите ему справиться с этим ... и не тратьте свое время, назначив null вещам. В самом деле, есть вероятность, что поля, которые вы обнуляете, находятся в объектах, которые все равно станут недоступными. И в этом случае GC даже не собирается смотреть на поля, которые вы обманули.

Если вы принимаете этот (прагматичный) взгляд, все ваше мышление о неглубоких и глубоких копиях и когда это безопасно для нулевых вещей, является спорным.


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

4

Чтобы очистить переменную

По моим сведениям,

Если вы собираетесь повторно использовать переменную, а затем использовать

   Object.clear(); 

Если вы не собираетесь повторно использовать , затем определите

   Object=null; 

Примечание: Сравнить removeAll(), clear() быстрее.

Пожалуйста, поправьте меня, если я ошибаюсь ....