views:

142

answers:

4

I wish to confirm which scenario will cause a Garbage Collection on the object myObj:

Scenario 1

ArrayList arList = new ArrayList();
while(someCondition)
{
  myObj = new MyObect(); // a custom object
  arList.add(myObj); 
}

Scenario 2

ArrayList arList = new ArrayList();
while(someCondition)
{
  myObj = new MyObect(); // a custom object
  arList.add(myObj); 
  myObj=null;
}

Does explicitly setting an object as null improves garbage collection behavior or will be it same when I reset the object using the new constructor ?

+5  A: 

Setting it to null will have no effect, since the object is still reachable via arList.

That is, your MyObect instances will live at least as long as arList.

EDIT: Based on your comment, it does sound like myObj is longer-lived. In that case, set it to null after the end of your loop.

ZoogieZork
+6  A: 

You don't specify the scope of myObj and its important. If its a local variable it almost certainly doesn't matter. If its an instance variable then that could be a long-lived and unnecessary reference in which case setting to null will be useful.

Update: given the updated information that myObj is local to the method, it will be of zero value to set it to null at the end of each iteration of the loop. Consider this example:

public void process(String text) {
  String[] lines = text.split("\n");
  List<MyObject> list = new ArrayList<MyObject>();
  Object myObj;
  for (String line : lines) {
    myObj = new MyObject(line);
    list.add(myObj);
    // 1. set myObj = null here
  }
  list = null; // 2
  // 3. do some other stuff
}

public class MyObject {
  private final String line;

  public MyObject(String line) {
    this.line = line;
  }
}

Now in this example, let's say that at step 3, it took a long time. Say 10 minutes. During that 10 minutes myObj is pointing to the last line processed. Doesn't sound like a problem? Well it could be. The way substrings work in Java is that they reference the original string. So if you do:

String s = ... // 100 megabytes
String s2 = s.substring(100, 101);

you're actually keeping the entire 100MB in memory because s2 references s.

So in the function I have above, myObj references a line which references the entire file. Changing step 1 to myObj = null; would actually help that because this reference is preventing the object being garbage collected.

Note: step 2 is important here because if you didn't nullify the list all the references would exist anyway.

You just need to think about how references work. An object won't be garbage collected while a reference to it exists. This means clearing long-lived references and keeping variables scoped as tightly as possible. The correct solution for the above is:

for (String line : lines) {
  Object myObj = new MyObject(line);
  ...
}

and then myObj is scoped inside the loop so as soon as the loop ends or another iteration begins it has gone out of scope, which is much better.

cletus
added scope of myObj . Its local to the method
Ravi Gupta
Thanks heaps, I guess I was facing a problem of similar kind
Ravi Gupta
@Ravi: you're welcome. :)
cletus
+1  A: 

Because it is in a while, myObj is always overwritten (the reference). So in Scenario 1 only one object (the last added in arList) will not be null.

It would be better if you declare it in the while statement:

while(someCondition)
{ 
  MyObect myObj = new MyObect(); // a custom object
  arList.add(myObj);  
}
True Soft
will this make myObj to be garbage collected after the loop exits ?
Ravi Gupta
@Ravi No, again, because the object was added to `arList`. It will be eligible for garbage collection when there are no more references to `arList`.
ZoogieZork
Thanks, I guess I got my answer.
Ravi Gupta
+2  A: 

I think that this is the root of your misunderstanding.

hmm.. but I don't wish to keep 2 copies of myObj , one in arList and one in the original variable. How can I flush myObj once I add it to arLsit ?

You do NOT "keep two copies of myObj". In your examples, there is only ever one "copy" of each MyObject instance created by the loop. The sequence is:

  1. You create a MyObject instance, assigning its reference to myObj.

  2. You add the reference to the instance to the ArrayList that arList refers to.

  3. You assign null to the reference in myObj.

Note that adding the reference to the list does NOT create a copy of the MyObject instance. It simply means that that you have the reference in two places instead of one. And when you assign the null you once again have the reference in just one place.

The other thing to note is that assigning null to something will never CAUSE the garbage collector to run. All it does is to (explicitly) remove a potential copy of a reference from consideration the next time the garbage collector is run.

Finally, if we assume that the scoping is as follows, then the line C will have no discernible effect ... unless either line A or line B triggers a garbage collection.

{
    MyObject myObj;
    ArrayList arList = new ArrayList();
    while (someCondition) {       // A
         myObj = new MyObect();   // B
         arList.add(myObj); 
         myObj = null;            // C
    }
}
Stephen C
Yes, I was bit confused about this, thanks for clearing my doubts. You guys are awesome.
Ravi Gupta