The client-side distributed garbage collector implementation currently makes use
of the automatic invocation of the finalize method of sun.rmi.transport.LiveRef
to determine that a given remote reference is no longer locally reachable in the
client VM. This approach has several problems:
- The timeliness of Java finalizers is barely specified (they will get executed
before the storage for the object is reclaimed). There is no guarantee that
they will ever run in a finite period of time, even if the garbage collector
executes an arbitrary number of full mark and sweep cycles. They are likely
executed by a low priority system thread.
- It is difficult to execute complex tasks with finalizers. The execution
context of a finalizer is delicate. A typical VM will have a thread that
executes pending finalizers in series, so a finalizer must return before all
other finalizers in the VM can execute. Also, a typical VM may attempt to
execute some finalizers synchronously as part of the steps taken to satisfy
a memory allocation request before throwing an OutOfMemoryError, which means
that an arbitrary memory allocation may block while an unrelated finalizer
is executing. Even worse, if a finalizer wishes to take non-trivial actions,
like modify shared data structures, it will likely need to synchronize on
shared locks; if another thread already owns such a lock and then attempts to
allocate memory, deadlock could result if the allocation causes the GC to
synchronously execute such a finalizer. Along the same lines, there are bugs
in most existing Java implementations that allow finalizers to be run
synchronously in arbitrary threads, like when the System.runFinalization()
method is called; this is in violation of the JLS (see bugid 4026895) because
finalizers are supposed to be guaranteed to execute in a thread that holds
no "user-visible synchronization locks". This means that a finalizer can
acquire a lock when the state guarded by that lock may be inconsistent (the
caller of runFinalization() probably isn't prepared for this phenomenon; at
least this doesn't happen for synchronous finalization during arbitrary
memory allocation like it did in 1.1.x). In summary, the delicate execution
context of finalizers makes it difficult or dangerous to use them for
non-trivial tasks.
- Finalizers can resurrect objects that have already been finalized. A cycle of
finalizable objects can be finalized in any order; therefore, a remote
reference that has already had its reference count decremented (because its
LiveRef's finalizer has run) can be completely resurrected by another
finalizer, remote calls can be made through it, etc., without the client
participating in DGC for the remote object.
The new class java.lang.ref.PhantomReference provides a facility that solves all
of these problems: detection of phantom reachability is detected by the garbage
collector proper, customers of phantom references can process them with
whatever timeliness they can muster (in threads of any priority, for example),
and phantom references guarantee that their referent can never be resurrected.
The DGC should use phantom references, not finalizers, to track the reachability
of remote references in a client VM.
of the automatic invocation of the finalize method of sun.rmi.transport.LiveRef
to determine that a given remote reference is no longer locally reachable in the
client VM. This approach has several problems:
- The timeliness of Java finalizers is barely specified (they will get executed
before the storage for the object is reclaimed). There is no guarantee that
they will ever run in a finite period of time, even if the garbage collector
executes an arbitrary number of full mark and sweep cycles. They are likely
executed by a low priority system thread.
- It is difficult to execute complex tasks with finalizers. The execution
context of a finalizer is delicate. A typical VM will have a thread that
executes pending finalizers in series, so a finalizer must return before all
other finalizers in the VM can execute. Also, a typical VM may attempt to
execute some finalizers synchronously as part of the steps taken to satisfy
a memory allocation request before throwing an OutOfMemoryError, which means
that an arbitrary memory allocation may block while an unrelated finalizer
is executing. Even worse, if a finalizer wishes to take non-trivial actions,
like modify shared data structures, it will likely need to synchronize on
shared locks; if another thread already owns such a lock and then attempts to
allocate memory, deadlock could result if the allocation causes the GC to
synchronously execute such a finalizer. Along the same lines, there are bugs
in most existing Java implementations that allow finalizers to be run
synchronously in arbitrary threads, like when the System.runFinalization()
method is called; this is in violation of the JLS (see bugid 4026895) because
finalizers are supposed to be guaranteed to execute in a thread that holds
no "user-visible synchronization locks". This means that a finalizer can
acquire a lock when the state guarded by that lock may be inconsistent (the
caller of runFinalization() probably isn't prepared for this phenomenon; at
least this doesn't happen for synchronous finalization during arbitrary
memory allocation like it did in 1.1.x). In summary, the delicate execution
context of finalizers makes it difficult or dangerous to use them for
non-trivial tasks.
- Finalizers can resurrect objects that have already been finalized. A cycle of
finalizable objects can be finalized in any order; therefore, a remote
reference that has already had its reference count decremented (because its
LiveRef's finalizer has run) can be completely resurrected by another
finalizer, remote calls can be made through it, etc., without the client
participating in DGC for the remote object.
The new class java.lang.ref.PhantomReference provides a facility that solves all
of these problems: detection of phantom reachability is detected by the garbage
collector proper, customers of phantom references can process them with
whatever timeliness they can muster (in threads of any priority, for example),
and phantom references guarantee that their referent can never be resurrected.
The DGC should use phantom references, not finalizers, to track the reachability
of remote references in a client VM.
- relates to
-
JDK-4226268 (1.1.x) DGC client should not synchronize on global lock
-
- Closed
-