views:

195

answers:

6

If I have:

for (int i; i != 100; i++) {
    ArrayList<String> myList = buildList();
    //... more work here
}

Do I have to set myList to null at the end of my loop to get the GC to reclaim the memory it uses for myList?

+4  A: 

No you don't Guide to Java GC or How Java GC works

controlfreak123
Thanks for the link that's a good article.
shady
+5  A: 

Lord, no! Java's GC is much, much, much smarter than that.

Matt Ball
Well, if the result of `buildList()` overrides `finalize()` it will be disastrous. But let's hope the code is sane.
Martinho Fernandes
@Martinho: How so?
Mark Peters
Objects overriding finalize() gets very special treatment by the garbage collector.
Thorbjørn Ravn Andersen
Sure but I'm wondering how it leads to "disastrous" consequences.
Mark Peters
Because objects that override finalize are created along with a "finalizer object" that is responsible for tracking finalization and stuff. This increases the survival rate on gen 0 collections and pushes "finalizer objects" to higher generations, making them harder to collect. Look at the examples here: http://elliottback.com/wp/java-memory-leaks-w-finalize-examples/
Martinho Fernandes
@Martinho: I fail to see how anything in that article deals with the dangers of using finalize methods in loops but rather is a general caution against stupid implementations of `finalize()`, whether in a loop or not. So how does simply overriding `finalize()` lead to disastrous results?
Mark Peters
@Mark: Yeah, that article does not exactly showcase what I meant. The problem is that you're creating objects that most likely will end up in the old generations, and those will only be collected when you get a full collection. You can end up with out-of-memory errors depending on the loop.
Martinho Fernandes
@Martinho: I didn't think it was possible to get an OOME without a full collection. I'd really love to see an example of this. I can understand worse performance, but I would be really surprised to see an OOME.
Mark Peters
@Mark: Well, I doubt it would be a common occurence, but in extreme cases, it could happen. In any case, performance will suffer, that's for sure.
Martinho Fernandes
@Martinho: Could it? I haven't seen any evidence of that yet. Java is built around giving guarantees that certain things *won't* happen, even in extreme circumstances. If it could happen, and the Java specification says it can't, that's a very grave situation that would require critical bug reports, patches, etc.
Mark Peters
+7  A: 

The GC will automatically clean up any variables that are no longer in scope.

A variable declared within a block, such as a for loop, will only be in scope within that block. Once the code has exited the block, the GC will remove it. This happens as soon as an iteration of the loop ends, so the list becomes eligible for garbage collection as soon as each iteration of the loop finishes.

The scope of a variable is also why i would not be valid after your example loop.

Note that this only is the case if you use the variable only within the loop. If you pass it to another method that keeps a reference to it, your variable will not be garbage collected.

Alan Geleynse
I think he's more worried that objects assigned to `myList` in previous iterations of the loop will be GC'd, even while still in the loop. Not after the loop.
Mark Peters
Good point, I updated the answer to address that.
Alan Geleynse
I don't know if this answer is complete enough. First, integers and other values types are allocated on the stack and have nothing to do with the garbage collection. Second, myList may or may not be eligible for garbage collection; it depends on whether or not another reference is stored somewhere else in your code.
Outlaw Programmer
@Outlaw Programmer: "integers and other values types are allocated on the stack". Do you have a reference for this claim? I believe the JVM can choose whether to use heap or stack allocation, and will do so based on various heuristics. Or are you talking about primitive types?
sleske
It's true that variables on the stack would not be garbage collected, I was simply referring to variable scope. I edited the answer to mention other references though, that is a very good point that I missed.
Alan Geleynse
-1 GC does not clean up variables. And GC has nothing to do with `i`, that's a primitive stack variable, not an instance on the heap.
Ishtar
A: 

you don't have to bother about the garbage. Java GC will automatically do this. But my suggestion is that as a good developer, you have to make practise for freeing the garbage. As GC will take some proccesing time. So by taking care of ourself we will definetly increase the performance.

Anant
+2  A: 

The GC reclaims all unreachable instances, when ever it wants to. It does not GC variables.

The variables i and myList live on the stack. When the for loop ends(when they go out of scope), they will be pushed of the stack and so their memory reclaimed. The variables will then be gone. Setting the reference variable myList to null just before it goes away, really makes no difference (for GCing the instances). If GC will reclaim the memory for the instance myList referred too, really depends on whether you have another reference to the same instance.

Variables don't get GCed, instances do.

Ishtar
+3  A: 

It would probably help to understand the syntax behind of the for-loop. That's discussed in the JLS Section 14.14.1.

BasicForStatement:
    for ( ForInitopt ; Expressionopt ; ForUpdateopt ) Statement

...

Statement:
    StatementWithoutTrailingSubstatement
    ...

StatementWithoutTrailingSubstatement:
    Block
    EmptyStatement
    ExpressionStatement
    ...


Block:
    { BlockStatementsopt }

BlockStatements:
    BlockStatement
    BlockStatements BlockStatement

BlockStatement:
    LocalVariableDeclarationStatement
    ClassDeclaration
    Statement

Statement, as always, can be a single statement or a block (statements surrounded with curly braces). A block represents a new lexical scope and variables declared therein are local to that block only. What many people don't realize is that isn't unique to the for-loop. I can put a block statement anywhere in a method:

 public void someMethod() {

     {
         List<String> myList = new ArrayList<String>();
         System.out.println(myList);
     }
     System.out.println(myList.size()); //compile error: myList out of scope
 }

Anyway this isn't going where I was intending. Suffice to say that it has less to do with the fact that it's a loop and more to do with the fact that it's a block (if you choose not to use a block statement, you can't declare new local variables so the problem is irrelevant).

Mark Peters
Does this mean that the GC is not used to manage the memory for variables/instances declared within a block? Once the block has ended, the variables/instances are reclaimed automatically?
shady
No, it doesn't mean that. Instances are still put on the heap and reclaimed by the gc. Remember the block could easily leak a reference to one of those instances. All I was trying to say was that the scope of a variable is limited to a block, regardless of the control structure being used.
Mark Peters