[concurrency-interest] [Javamemorymodel-discussion] Fences.keepAlive

Boehm, Hans hans.boehm at hp.com
Wed Jan 14 14:16:36 EST 2009

> From:  Matthias Ernst
> On Wed, Jan 14, 2009 at 6:45 PM, Gregg Wonderly 
> <gregg at cytetech.com> wrote:
> > Can someone elaborate why the reference on the stack as a 
> local value 
> > would not maintain a reference that lasted until the method exits?
> Why would it? The object will no longer be used in the rest 
> of the method, why keep it alive?
> So it is totally conceivable that the stackmap will no longer 
> announce this reference to the GC even if the value is still 
> somewhere on the stack or in a register.
> I would even expect a clever optimizer to reuse the storage, 
> so the reference is "physically" gone.
Exactly.  And the value may in fact no longer be on the stack or in a register.  Most modern calling conventions (e.g. on X86-64, less so on X86-32) pass arguments in registers.  Thus even if the object was allocated by the caller, by the time it's passed to the current method, where it becomes "this", it may only live in an argument register, which the callee is allowed to overwrite once it's dead.

This has nothing to do with java.lang.ref vs. finalization; the problem exists either way.  It also has little to do with native code, though that might aggravate the problem.

Currently any method that touches "external" object state that may be cleaned up by the objects finalizer, should execute something like
"synchronized(this) { }" at the end of the method in order to prevent premature cleanup of the external state.  I conjecture that 90+% of such code is currently broken.  It rarely fails, since implementations usually happen to keep the relevent pointer (not always "this") live longer anyway.  And X86-32's lack of registers for calling conventions probably also helps, a bit.  And even if the resulting code is wrong, it will only fail once ina blue moon.

There are other possible design tradeoffs, but they're more invasive.  Outlawing dead variable elimination for object references works, and was discussed during JSR133 discussions.  At the time it we felt that this was risking too much performance impact for a rarely used language feature.  Although I advocated this position (in part to help get JSR133 out the door), I think that from a purely technical perspective it's worth considering.

Although C++0x is expected to contain only very minimal GC support, and no finalization support, this issue was discussed in some detail in that context, and I think the options could probably all be adapted to Java.  This is largely written up at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2261.html .

> It is also important to note that this topic is very related 
> to the memory model. The last point of reachability is just 
> as much subject to reordering/inlining optimizations and an 
> object can end up being collected even earlier than its last 
> lexical reference.
Right.  And JSR133 at least made the symchronized(this) solution possible.  But we always knew that this wasn't a great solution.  I think keepAlive is really the minimal solution that people might realistically pay attention to.  I have to admit I'm not encouraged by the .NET documentation that Matthias pointed to, since it also seems to miss the core problem and focus on native code issues instead.

> Matthias

More information about the Concurrency-interest mailing list