What happens if you save a reference to the current object during the finalize call? For example:
class foo {
...
public void finalize() {
bar.REFERENCE = this;
}
}
Is the object garbage-collected, or not? What happens when you try to access bar.REFERENCE
later?
The object is not garbage collected. This is know as "Object resurrection".
You must be careful with that, once the finalizer is called the gc won't call it again, on some enviroments like .NET you can re-register the finalizer but i'm not sure about java
If you absolutely must resurrect objects, this JavaWorld article suggests creating a fresh instance rather than resurrecting the instance being finalized because if the instance being finalized becomes eligible for collection again it will simply be collected (the finalizer won't be run again).
This kind of thing is the reason why the use of finalize()
is generally discouraged.
Because Java is a safe language and platform, the memory is not freed. Also associated PhantomReference
s will not be enqueued upon their ReferenceQueue
s. The VM will only ever call finalize
on an object once. There's a nice state diagram in the JVM Spec.
Typically if you do use a finaliser, you should leave the declaration as @Override protected void finalize() throws Throwable
, so as not to disturb the API. Even better use a guarded finaliser, as in Effective Java 1st Ed.
This particular trick hit the headlines (of the San Jose Mercury, anyway) when a group at Princeton used it to construct a custom ClassLoader
from untrusted code. Although the spec has been slightly tightened (the Object
constructor has to finish executing normally before the finaliser can be called - specified in J2SE 5.0, implemented in Java SE 6), this still remains a problem area. If you are designing an API, make sure sensitive classes cannot be subclasses and save yourself much grief.
The finalize()
method may be invoked explicitly on the foo
instance, or it may be invoked by the garbage collector when it tries to reclaim the storage occupied by that object.
If bar
is a valid instance, it sets the REFERENCE
field to the foo
instance. From the garbage collector's point of view, this increases foo
's reference count.
If an exception is thrown inside the finalize()
method (e.g. such as a NullPointerException
due to bar
being null
), then the finalization process simply terminates.
N.B. As others have pointed out.. your example is definitely something to be avoided.