As the Java Virtual Machine doesn't allow explicit freeing and allocating of memory, an automatic garbage collection thread must be run to detect and remove objects in memory that are no longer accessible.
The way that the garbage collector actually gets rid of inaccessible objects is to call their finalizer. The default finalize() method is defined in java.lang.Object:
protected void finalize() throws Throwable { }
This method can be overridden so that any resources associated with the object can be released cleanly (e.g. network connections torn down). Also, it can be useful when debugging a programme, as garbage collection can be tracked on an object-by-object basis if you place code like this:
protected void finalize() throws Throwable {
System.out.println("Object garbage collected: "+this.toString()};
}
Data describing the current state of the garbage collected object can also be output.
Problems
As finalizer methods can be run by any thread at any time, unexpected behaviour can occur when objects are garbage collected.
One such problem is that mutual exclusion locking systems can be violated. Consider the following situation:
- a running thread is holding a lock
- garbage collection occurs, maybe due to the thread calling System.gc()
- the thread runs a finalizer on an object which requires the same lock to be gained
- the thread enters the same synchronized block
As locks in Java are recursive, a thread is allowed to gain the same lock twice, so the above steps are perfectly legal. However, having two threads of control executing code which is supposed to be mutually exclusive is clearly not what designers, or users, want.
Another problem is that a finalizer can make an object persistent if a new instance is created inside that finalizer:
public class TestFinalize {
public void finalize() {
new TestFinalize();
}
}
At first, this seems stupid - why would anyone deliberately break their own code? However, if a call to some poorly understood method is made in the constructor, it could be that the method creates a new instance of the class as part of its execution. Although the two classes are different, and cannot be confused, having an object garbage collected and creating a new instance at the same time is clearly dangerous.