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

Gregg Wonderly gregg at cytetech.com
Wed Jan 14 15:30:30 EST 2009

Boehm, Hans wrote:
>> 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?

I guess I'm trying to wrap my brain around which issue we are discussing.

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

Okay, but the objects life continues as long as someone is referencing it and I 
have no problem understanding the lifecycle for 100% Java stuff.

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

But PhantomReference makes finalize() unnecessary when you use the Holder 
pattern that my ReferenceTracker is based on.  With that pattern, you don't have 
anything going on "bad" because the Tracker has a strong reference to the 
"to-be-released" resource and when the Holder goes out, the Tracker knows which 
object to use for "releasing" the associated resource(s).  Every object that has 
associated resources can be dealt with in this way, and any ordering 
requirements can all be managed via strong references where you are in complete 
control of the order of operations.

My Tracker is much like the S object in your paper, so I think you familiar with 
where I'm coming from.

 From my perspective, one can stop using finalize and worrying about all these 
data races by just adopting the pattern that I'm presenting through the use of 
my ReferenceTracker class.

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

I personally don't want to see this level of GC implementation detail visible to 
the developer and a necessary part of their programming knowledge.  finalize() 
has way too many bad things in it related to ordering etc.  Your paper talks 
about these things in great detail.  Exposing them will interfere with the JMM 
and the GC details if they are made more controllable.

Rather than say we need a fence at the end of finalize(), why not, instead say, 
use class XYZ to track references to resources you need to release at the end of 
an objects life.  Then we have a more flexible way to manage this issue it seems 
to me, and there is not the low level detail of locking that the developer has 
to deal with.

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

It still seems to me that PhantomReference is the better solution than 
finalize(), maybe you can tell me why that isn't the case.

> I think keepAlive is really the minimal solution that people might 
> realistically pay attention to.

It seems that the .NET solution is to just provide a standard method name which 
does nothing, so that the compiler is compelled to maintain order of execution 
and to maintain the reference till the end of the method.  Is there something 
else happening here?

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

Hans, are you only talking about how finalize() works, or is there another path 
in 100% java code that I still haven't gleaned from this?

Gregg Wonderly

More information about the Concurrency-interest mailing list