RE: JavaMemoryModel: A problematical case for finalizers

From: Boehm, Hans (hans_boehm@hp.com)
Date: Thu May 22 2003 - 12:51:30 EDT


Jerry -

I have some problems with both of these. Specifically:

A. I think this doesn't interact well with inheritance. If you let the programmer do the synchronization, it's his/her responsibility to decide what the interesting last operations on the object could be. If you require that the implementation does it automatically, I expect you end up with those release stores all over the place. For example, presumably the default implementation of Object.hashcode() and Object.clone() needs the release store, because some class that inherits from it will have a finalizer, and it logically accesses a field? You might be able to have two versions of these operations, and implicitly override the simpler one when you add a finalizer, but this starts to sound nontrivial, both in the implementation and the spec.

You really want to apply the volatile store treatment only to methods that can access the resource requiring finalization, and those are probably not in the ancestor classes. But I'm not sure the compiler has quite enough information to identify the right methods. And identifying them in the spec sounds messy.

What if a method accesses multiple instances of a class with a finalizer, with some passed as a parameter? What if you're using a finalizer guardian and the actual handle needing cleanup is in a parent class?

I think that getting this right is likely to lead to a complex spec with optimization impacts that we don't understand.

B. We do explicitly allow optimizers to violate the naive semantics of Java by reordering ordinary reads and writes, and by not inserting memory barriers between all memory operations. (This relaxation probably results in a factor of 10-100 performance improvement on many architectures, so it's probably a good thing.) The JLS currently doesn't specify "naive" reachability. Given that memory operations can be reordered around the end of a block, I think it would be hard to do so. Thus I don't know how to make this precise.

Hans

> -----Original Message-----
> From: Jerry Schwarz [mailto:jerry.schwarz@oracle.com]
> Sent: Tuesday, May 20, 2003 10:48 AM
> To: Boehm, Hans; 'Martin Trotter'; javaMemoryModel@cs.umd.edu
> Subject: RE: JavaMemoryModel: A problematical case for finalizers
>
>
>
> 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