RE: JavaMemoryModel: Finalizers

From: Boehm, Hans (hans_boehm@hp.com)
Date: Mon Apr 07 2003 - 15:25:27 EDT


> -----Original Message-----
> From: Bill Pugh [mailto:pugh@cs.umd.edu]
>
> As we've found in a number of instances, the appropriate semantics
> are those that leaves both the programmers and VM implementors
> grumbling, but neither screaming.
>
> Let's propose we amend JLS 12.6.1 to state clearly that any object
> that is referenced from a field or element of a reachable object is
> reachable.
I'm willing to tolerate the optimization implications of this.

I'm still concerned whether this all makes sense for plain references. But I'm starting to believe that it does. I've included the example I was thinking about, in case someone can find an error in my reasoning:

Finalizer ordering is probably the most important example to think about. If you can't enforce ordering there are lots of things that can't be done.

Assume we have class A, with a finalizer that refers to an OutputStream field os, say to write a log message and then close the stream. Assume that each output stream is referenced only by a single A object.

A's constructor needs to add os to some globally reachable data structure, so that a possible finalizer associated with os can't run before A's finalizer and close the stream prematurely. (Note that os may not actually have a finalizer. But an object referenced by it may. To make things clearer, we assume that os itself has a finalizer.) A's finalizer removes os from this global data structure. Assume all methods in finalizable classes are synchronized.

First assume the global data structure to keep things reachable uses regular, not volatile links. As os gets dropped, we effectively have two threads running:

Main thread Finalizer thread

invoke A.finalize()
  ...
  call os.close()
        lock os
        <do_something>;
        ...
        unlock os
  ReachableStruct.remove(os)
        ... = null; invoke os.finalize
                                                  lock os
                                                  ...
                                                  unlock os

The problem is that the "= null" assignment to remove the entry from ReachableStruct can potentially become visible just before any writes performed by <do_something>. Hence os' finalizer may become runnable earlier than expected (which is what I was worried about. But I think the existing synchronization takes care of the problem, and this all works. Does this sounds right?

> Do any of the VM implementors want to scream?
Gcj/gij isn't likely to remove fields for many reasons.
>
> Secondly, what about the other ideas I proposed in Saturday's email:
>
> * the keepAlive method
I think something like this may be needed if we discover that fully synchronizing finalizable classes is too much of a performance hit. I agree that it feels like a hack, and I'd be happy not to include it unless/until we know it's unavoidable.
>
> * rule on locks keeping objects reachable
This is still essential.
>
> * freeOnceGarbageCollected
I don't like it. There are way too many possible protocols for deallocating a "native" object ("free", C++ "delete", STL deallocation, library-specific calls, ...)
>
> * runOnceGarbageCollected
Given the above rule, this is unnecessary, right? (And that's a good thing ...)

Hans



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