سؤال

I was recently looking into freeing up memory occupied by Java objects. While doing that I got confused about how objects are copied (shallow/deep) in Java and how to avoid accidently clearing/nullifying objects while they are still in use.

Consider following scenarios:

  1. passing a ArrayList<Object> as an argument to a method.
  2. passing a ArrayList<Object> to a runnable class to be processed by a thread.
  3. putting a ArrayList<Object> into a HashMap.

Now in these case, if I call list = null; or list.clear();, what happens to the objects? In which case the objects are lost and in which cases only the reference is set to null?

I guess it has to do with shallow and deep copying of objects, but in which cases does shallow copying happens and in which case does deep copy happens in Java?

هل كانت مفيدة؟

المحلول

Firstly, you never set an object to null. That concept has no meaning. You can assign a value of null to a variable, but you need to distinguish between the concepts of "variable" and "object" very carefully. Once you do, your question will sort of answer itself :)

Now in terms of "shallow copy" vs "deep copy" - it's probably worth avoiding the term "shallow copy" here, as usually a shallow copy involves creating a new object, but just copying the fields of an existing object directly. A deep copy would take a copy of the objects referred to by those fields as well (for reference type fields). A simple assignment like this:

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

... doesn't do either a shallow copy or a deep copy in that sense. It just copies the reference. After the code above, list1 and list2 are independent variables - they just happen to have the same values (references) at the moment. We could change the value of one of them, and it wouldn't affect the other:

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

Now if instead of changing the variables, we make a change to the object that the variables' values refer to, that change will be visible via the other variable too:

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

So back to your original question - you never store actual objects in a map, list, array etc. You only ever store references. An object can only be garbage collected when there are no ways of "live" code reaching that object any more. So in this case:

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

... the ArrayList object still can't be garbage collected, because the Map has an entry which refers to it.

نصائح أخرى

To clear the variable

According to my knowledge,

If you are going to reuse the variable, then use

               Object.clear();

If you are not going to reuse, then define

               Object=null;

Note: Compare to removeAll(), clear() is faster.

Please correct me, If I am wrong....

It depends on how many variables are referenciating to each of your objects, to explain this it would be better some code:

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.

So it doesn't depend whether you pass your ArrayList as an argument to a method or the like, it depends on how many variables are still refering to your objects.

If you passed an ArrayList to a method then list = null will have no effect if there is a live reference to the list somewhere eg in the calling code. If you call list.clear() anywhere in the code the references to the objects from this list will be nulled. Passing a reference to a method is not shallow copying it is passing reference by-value

Java GC automatically claims the objects when they are not referenced anywhere. So in most cases you will have to set the reference as null explicitly

As soon as the scope of the variable ends the object becomes eligible for GC and gets freed up if no other reference points to the object.

Java is pass by value so if you set the list as null in the method then it will not affect the original reference that was passed to you in the method.

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

If you put the list into a hash map, the hash map now holds a reference to the list.

If you pass the list as an argument to a method, the method will have a reference to it for the duration of the method.

If you pass it to a thread to be manipulated, the thread will have a reference to the object until it terminates.

In all of these cases, if you set list = null, the references will still be maintained, but they will disappear after these references disappear.

If you simply clear the list, the references will still be valid, but will now point to a list that has suddenly been emptied, by means that may be unknown to the programmer and may be considered a bug, especially if you use the thread.

I was recently looking into freeing up memory occupied by java objects.

A piece of advice.

It is usually a bad idea to think about this. And it is usually a worse idea to try to "help". In 99.8% of cases, the Java garbage collector is able to do a better job of collecting the garbage if you actually just let it get on with it ... and don't waste your effort by assigning null to things. Indeed, the chances are that the fields you are nulling are in objects that are about to become unreachable anyway. And in that case, the GC is not even going to look at the fields that you've nulled.

If you take this (pragmatic) view, all your thinking about shallow versus deep copies and when it is safe to null things is moot.


There is a tiny percentage of cases where it is advisable to assign null ... to avoid medium or long term storage leaks. And if you are in one of those rare situations where it is "recycling" objects is actually a good idea, then nulling is also advisable.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top