RE: JavaMemoryModel: A problematical case for finalizers

From: Jerry Schwarz (jerry.schwarz@oracle.com)
Date: Tue May 20 2003 - 13:47:31 EDT


I propose the following two changes

A. Bill Pugh's suggestion that a class with a finalizer has an implicit
volatile field that is written by all operations that access the fields of
the instances of that class and read by the finalizer.

B. Remove the permission that allows "optimizers" to violate the naive
semantics of Java. We don't do that for any other semantics, we shouldn't
do it for finalizers.

I don't think anyone would object to these on functional grounds. The only
objections I can imagine are on performance grounds. There would
potentially be some performance penalty for these, but it is hard to
predict how much and it is hard to compare it to the overheads implied by
all the synchronize's that are needed in the absence of these changes.

If implemented naively the penalty from A is comparable to that of
synchronizing everything as Hans advocates. However, because the pattern of
use of this volatile is very specific the system might be able to optimize
more effectively than it could do if just presented with the raw
synchronization. For example, it can take advantage of any memory barriers
in it's gc.

The penalty from B is harder to measure, but note that usually it requires
no extra operations. Its cost is mostly in register usage. In the most
common situations, where access to fields is only via methods of the class,
the cost on many systems would be zero.

This doesn't eliminate the problems associated with Hans' reason (3), but
it does make dealing with them much simpler. In a typical case where
finalize is something like

     void finalize() { close(); /* release os resources */ }

The issues associated with finalize will be exactly the same as those of
multi-threading in general and no special care would need to be taken
beyond whatever already needs to be taken to deal with one thread calling
close() while another thread is performing some other operation.

At 11:15 AM 5/19/2003, Boehm, Hans wrote:
>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

-------------------------------
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