RE: JavaMemoryModel: A problematical case for finalizers

From: Boehm, Hans (hans_boehm@hp.com)
Date: Mon May 19 2003 - 14:15:10 EDT


There are really at least three reasons to synchronize finalizers and
other externally visible methods in that class:

1) To prevent premature execution of the finalizer before the last
method call. I believe that for most current implementations that
do any sort of optimization, this is necessary. I started this discussion
by proposing to make it sufficient. With the current spec it isn't sufficient.
I believe it is sufficient for all common JVMs.

2) To ensure visibility too the finalizer of memory accesses that occurred
while the object was live. As Martin observed, current JVMs generally
ensure that anyway, even without explicit synchronization, except for
compiler reordering issues. In spite of what Bill and Jeremy's old proposal
said, and I originally agreed to, I think it's clear now that ensuring
visibility for accesses to the object itself is insufficient. Finalizers
generally aren't used unless some of the interesting state is outside the
object.

3) Even for a completely naive implementation on a sequentially consistent
machine (or a uniprocessor) a finalizer may still be run concurrently with
another method on the object, though this typically indicates a bug or
a malicious client. If you define a class A with a finalizer and a method foo()
which is unsafe to run concurrently with the finalizer, I can define
class B with a field that has the only reference to an A object a, and
a finalizer that repeatedly invokes a.foo() in a loop. This makes it quite
likely (possibly after some tweaks to allow for JVM idiosyncrasies) that
a.foo() and a.finalize() will run concurrently.

In all cases, if you fail to synchronize, the failure probability is
small, at least in the absence of malicious code. But it is nonzero.

I would be very interested in a proposal that

a) Makes finalization simpler, and more exiting code correct, and

b) Interacts reasonably cleanly with the rest of the memory model, and

b) Doesn't have a dramatic negative impact on optimization of classes
without finalizers.

But I think the most important steps in fixing this are:

1) Agree on a proposal that makes it possible to write correct code
with finalizers.

2) Convince authors to fix Java textbooks.

Some of the finalizer-related discussion in current textbooks is so far
off track that I would expect a lot of existing code that uses finalizers
to be in need of repair no matter what we do. (E.g. at least one recommends
that finalizers be used to clear circular references to make life easier
for the garbage collector. I haven't seen any textbook discussion
of finalizers that I think would be adequate to teach correct usage.
And without (1), that's certainly understandable.
The slides from my POPL talk, which basically lists finalizer myths, are at
http://www.hpl.hp.com/personal/Hans_Boehm/popl03/slides.pdf )

Hans

> -----Original Message-----
> From: Martin Trotter [mailto:martin_trotter@uk.ibm.com]
> Sent: Monday, May 19, 2003 5:49 AM
> To: javaMemoryModel@cs.umd.edu
> Subject: RE: JavaMemoryModel: A problematical case for finalizers
>
>
>
> I quite agree that the finalization model needs to be as intuitive as
> possible and don't believe that in most cases programmers
> should need to
> put explicit synchronisation into the finalize method to get
> the behaviour
> they expect; that the results of operations done in the
> methods of a class
> are available to the finalize method of that class. I
> previously appended
> the following to the discussion but nobody has commented further. I
> believe that most if not all existing JVMs do the right thing
> and that we
> should at least specify as much in JSR133.
>
> ------- previous append ------------
> I have been re-reading the discussion on finalizers. The
> general trend of
> the discussion is that all finalizers should be synchronized
> since they can
> be run on a separate thread. I don't believe that for most
> usages and most
> (if not all VMs) that rule is actually correct. The process
> of identifying
> objects to be finalized actually has the effect of ensuring
> that the GC
> thread (whichever that is) is guaranteed to have seen the
> last write to the
> object at the point that it realises that there are no
> remaining strong
> references to the object. So, does the GC thread pass on
> that guarantee to
> the finalizer thread ? I believe that in current VMs it does
> since the
> process involves a monitor controlling a list of
> to-be-finalized objects.
> If the VM chose to employ some atomic operation not involving memory
> barriers then of course the guarantee would not be passed on.
> However, in
> general a single monitor operation will perform much better than many
> atomic operations and thus I believe that current VM's would have no
> problem in making the guarantee that a finalizer will behave
> as if there
> existed a 'finalization lock' on the object. This lock is
> released after
> the last update of the object and obtained by the finalize
> method. For a
> large class of users this guarantee would be all they needed
> to avoid them
> worrying about synchronization simply as a consequence of the
> VMs decision
> to employ a separate finalizer thread.
> --- end of previous append ---------
>
> I think I'm right in saying that the proposal is to add the
> guarantees that
> you are looking for to Thread.join etc. That's already a
> part of JSR 133.
>
> Martin Trotter
>
> mtrotter@uk.ibm.com
>
> -------------------------------
> JavaMemoryModel mailing list -
http://www.cs.umd.edu/~pugh/java/memoryModel
-------------------------------
JavaMemoryModel mailing list - http://www.cs.umd.edu/~pugh/java/memoryModel



This archive was generated by hypermail 2b29 : Thu Oct 13 2005 - 07:00:44 EDT