Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should variables be declared inside the loop or outside the loop in java [duplicate]

I know similar question has been asked many times previously but I am still not convinced about when objects become eligible for GC and which approach is more efficient.

Approach one:

for (Item item : items) {
    MyObject myObject = new MyObject();
    //use myObject.
}

Approach Two:

MyObject myObject = null;
for (Item item : items) {
    myObject = new MyObject();
    //use myObject.
}

I understand: "By minimizing the scope of local variables, you increase the readability and maintainability of your code and reduce the likelihood of error". (Joshua Bloch).

But How about performance/memory consumption? In Java Objects are Garbage collected when there is no reference left to the object. If there are e.g. 100000 items then 100000 objects will be created. In Approach One each object will have a reference (myObject) to it so they are not eligible for GC?

Where as in Approach Two with every loop iteration you are removing reference from the object created in previous iteration. so surely objects start becoming eligible after the first loop iteration.

Or is it a trade off between performance and code readability & maintainability?

What have I misunderstood?

Note: Assuming I care about performance and myObject is not needed after the loop.

Thanks In Advance

like image 391
webDeveloper Avatar asked Feb 10 '23 23:02

webDeveloper


1 Answers

If there are e.g. 100000 items then 100000 objects will be created in Approach One and each object will have a reference (myObject) to it so they are not eligible for GC?

No, from Garbage Collector's point of view both the approaches work the same i.e. no memory is leaked. With approach two, as soon as the following statement runs

myObject = new MyObject();

the previous MyObject that was being referenced becomes an orphan (unless while using that Object you passed it around, say, to another method where that reference was saved) and is eligible for garbage collection.

The difference is that once the loop runs out you would have the last instance of MyObject still reachable through the myObject reference originally created outside the loop.


Does GC know when references go out of scope during the loop execution or it can only know at the end of method?

First of all there's only one reference, not references. It's the objects that are getting unreferenced in the loop. Secondly, the garbage collection doesn't kick in spontaneously. So forget the loop, it may not even happen when the method exits.

Notice that I said, orphan objects become eligible for gc, not that they get collected immediately. Garbage collection never happens in real time, it happens in phases. In the mark phase, all the objects that are not reachable through a live thread anymore are marked for deletion. Then in the sweep phase, memory is reclaimed and additionally compacted much like defragmenting a hard drive. So, it works more like a batch rather than piecemeal operations.

GC isn't bothered about scopes or methods as such. It only looks for unreferenced objects and it does so when it feels like doing it. You can't force it. The only thing that you can be sure of is that GC would run if the JVM is running out of memory but you can't pin exactly when it would do so.

But, all this does not mean that GC can't kick in while the method executes or even while the loop is running. If you had, say, a Message Processor that processed 10,000 messages every 10 mins or so and then slept in between i.e. the bean waits within the loop, does 10,000 iterations and then waits again; GC would definitely kick into action to reclaim memory even though the method hasn't run to completion yet.

like image 118
Ravi K Thapliyal Avatar answered Feb 13 '23 21:02

Ravi K Thapliyal