Подтвердить что ты не робот

Очистка или установка нуля для объектов в java

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

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

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

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

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

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

               Object.clear();

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

               Object=null;

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

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

Ответ 3

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

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

Ответ 4

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

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

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

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

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

Ответ 5

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
    }
}

Ответ 6

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

Ответ 7

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

Несколько советов.

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

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


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