Reputation: 15952
Consider the following Java class:
class Main
{
private static Integer AddOne(Integer i) {
return i + 1;
}
public static void main(String[] args)
{
Integer one = new Integer(1);
System.out.println(AddOne(one));
}
}
In this simple example, it is easy to see that the object referred to by one
is never referenced again after the call to AddOne
. It will be garbage collected some time after main
exits. However, having the object around in memory until it is reaped is a waste--perhaps not so much for an Integer
, but if I had a large data structure (or many of them), it could impact performance.
It seems to me that a compiler could examine the above code and see that it is not possible for a reference to one
to escape the Main
class. Then, it could explicitly deallocate/finalize the reference at the end of the main
function.
Is such a facility present in any Java implementations? If not, is there a technical reason why such a mechanism would not work?
Upvotes: 1
Views: 236
Reputation: 48864
The JIT and recent advances in Java garbage collection makes exact answers to this sort of question difficult. But there are some things the JVM has to support, due to requirements of the language specification.
In particular, the JVM cannot garbage collect instance variables (e.g. an unused private field) even though it isn't touched by the bytecode, as a caller could still use reflection to inspect or access the element.
In your example, we're talking about a local variable, which is not handled the same way. Local variables are allocated on the stack, rather than the heap, and the garbage collector would have no problem cleaning it up as soon as the method returns (if not even sooner, in fact). It does not need to wait until the Main
class is unloaded. The Integer
object one
refers to would stay around longer than one
itself, but as soon as it's unreferenced, the GC will clean it up at the first opportunity.
I've no idea if this is true presently, but I would imagine it's possible for the compiler to even redesign code like this to entirely avoid Integer
, and use int
directly instead. The new
call in this example likely explicitly prevents that here, but substituting Integer.valueOf()
would avoid the explicit allocation request and potentially allow the compiler to avoid any object allocation at all.
That said of course, in this simple example it's unlikely the GC or the JIT would have enough time to try to clean anything up. Obviously you're just offering a simple example for the sake of discussion, but it's worth mentioning that the program's duration can have a big impact on what gets GC'ed or JIT'ed, and when.
It would be potentially possible to model/test some of this using WeakReference
, if I have time I'll try to revisit this answer with some example code / analysis.
You may also appreciate a similar question I asked last year: Can unused private variables be GCed before their holding instance?
Upvotes: 1
Reputation: 234847
This is not possible (at least for the Java Virtual Machine) because there is no JVM instruction for explicitly deallocating an object. (The instruction set can be found in Chapter 6 of the Java Virtual Machine Specification.) There really isn't a lot of waste in letting the GC do its job. Most implementations use incremental GC algorithms that are pretty good at noticing when things go out of scope fairly quickly.
I'm pretty sure that compilers and JIT compilers are pretty good at identifying dead variables, so one
would often go out of scope (and the Integer
subject to GC) right after its last use, regardless of what else was going on in main()
.
While in your example it is possible for the compiler to figure out that the object referenced by one
is eligible for GC, this relies on analyzing the operation of AddOne
to ensure that no other reference to the object is created. Even a slight increase in the complexity of the code would make this kind of static analysis almost impossible. So even if it were possible for the compiler to do what you suggest, I think the complexity of the analysis would make it useless to attempt to do so.
One further thought: If you changed the initialization of one
to:
Integer one = Integer.valueOf(1);
then it would be absolutely wrong for the Integer
to be deallocated at the end of main()
. This is because Integer.valueOf(1)
will almost certainly return a cached object maintained by the Integer
class. Because of the cache, the reference count would not be 0 until the Integer
class definition was unloaded (usually during JVM shutdown).
Upvotes: 1