[concurrency-interest] [Javamemorymodel-discussion] Fences.keepAlive
peger at automotive.com
Tue Jan 20 19:12:30 EST 2009
Thanks for the reference, couple comments below:
> I think it's very tricky to do this without essentially prohibiting
> dead variable elimination on references to Java objects. In
> limiting it to just "this" seems very weird to me. It fixes the most
> obvious examples. But if someone rewrites one of those member
> as a static function with an explicit object parameter, the code
> again. That would probably be even harder to explain than the
Wouldn't static functions be immune by virtue of not having access to
the member variables in the first place? IE all parameter objects are
already referenced (by the stack frame) for static methods?
> Solution 2 in http://www.open-
> std.org/JTC1/SC22/WG21/docs/papers/2007/n2261.html tries to contain
> effect to objects that appear finalizable. There's a handwaving,
> argument that that might make sense, but even that's unclear. The
> is that a reference to a non-finalizable P may actually refer to a
> subclasss that is finalizable. And thinking about it again, it almost
> certainly doesn't work in Java, since java.lang.ref effectively allows
> to finalize any object, no matter what its type.
I'm thinking that the JIT could mark/deoptimize the class on first
enqueue to a ReferenceQueue? This would switch the class to have the
same semantics as a non-empty finalize(), and could probably last as
long as the class definition is loaded into the VM. The finalizability
of a class would only be affected by the code generated by a concrete
subclass (though I do see that the parent class chain may need to be
compiled twice for optimal performance, once for finalizable subclasses
and once for non).
> It seems likely to me that the only clean solution would be to
> prohibit all dead variable elimination, effectively allowing it only
> provably can have no effect on finalization or reference enqueuing,
> would hence be invisible (except that space requirements may be
> In addition to increased register pressure in the compiler, this has
> cost in extra garbage retention by the collector.
With some brainwaving, I tend to think the GC overhead would be pretty
minimal with a modern generational GC. Register pressure (brainwaving
again ;-) I think could be reduced by shoving these possibly dead
pointers off to special L1/memory, that would only need to be read when
walking the stack for GC purposes.
> > Or alternatively,
> > B)
> > Have the JIT implicitly insert a keepAlive(this) directly
> > before the method return, for all classes having a non-empty
> > finalizer, in all methods that access the "this" reference.
> > This would have the advantage of "fixing" these broken
> > programs without possible breakage. The only issue I can see
> > here would be the possible performance impact.
> > Mitigating this i see a couple things: a) keepAlive(this)
> > could be a compiler intrinsic and so multiple keepAlive()
> > "calls" could be collapsed when inlining, etc. b) Coders have
> > been warned against
> > finalize() strongly for so long that this would only effect
> > those few classes for which they are already expecting a
> > performance hit.
> I think this is essentially equivalent to (A), with the same issues.
> Again, the performance hit is difficult to limit to classes that use
> finalization. C++ does manage to limit it to dead variable
> objects with destructors. But once you make heavy use of something
> C++ shared_ptr, there are a lot of those objects.
I think the big advantage Java has here over C++ is (as usual) dynamic
compilation, in this case driven by the "needs finalization-friendly
JIT" flag which AFAICS can be computed accurately. Of course I have not
done testing/hacking on any of this, though the OpenJDK does tempt ever
More information about the Concurrency-interest