RFR(M/L): 7145569: G1: optimize nmethods scanning

John Rose john.r.rose at oracle.com
Mon Jun 17 17:37:07 UTC 2013

On Jun 16, 2013, at 10:42 PM, Mikael Gerdin <mikael.gerdin at oracle.com> wrote:

> On 2013-06-16 22:30, Igor Veresov wrote:
>> On Jun 14, 2013, at 5:27 AM, Mikael Gerdin <mikael.gerdin at oracle.com> wrote:
>>> Just to make sure I understand this change, for the G1 class unloading work I don't want the nmethods to act as strong roots. So I guess I'll need to remove the call to mark_strong_code_roots.
>>> In the class unloading case only nmethods on the execution stack should be treated as strong roots and they are taken care of by Threads::possibly_parallel_oops_do (from process_strong_roots).
>> I think references to the _objects_ from nmethod must be strong, otherwise these objects will be only weakly referenced most of the time and will be collected (since they are usually only referenced by that particular nmethod) and you'll be forced to kill nmethod pretty much every collection to stay consistent. References to _classes_ on the other hand should be weak, I think.. Right?
> How do you mean?
> I'm not entirely clear on when an object is _only_ reachable from an nmethod. Is that a common case? I don't see how this is different in G1 than in any of the other collectors.
> Anyway we are unable to make the distinction between objects and classes referenced from nmethods now since we use the ClassLoader java object to reference the Klass*/Method* from an nmethod.

See the comment in nmethod.cpp for nmethod::oops_do.  There may be a mix of strong and weak roots in nmethods (as one might expect).

Roots for random constants compiled by the JIT into machine code are usually strong not weak.  The cost of putting a weak root in an nmethod is that the nmethod has to be recompiled if the object goes away (or there is a bug when the code uses a null pointer left behind).  The cost of a strong root is retaining an object that should have been GCed or (worse) a class that could have been unloaded.

For example, if code has an interned string constant there is no benefit for flushing the code if nobody else uses the string.  Same point for invokedynamic call sites.  But these examples do not strictly require nmethod strong roots, though, since the oops are already rooted in the constant pool for the method.

More subtle examples are oops which the JIT has constant-folded by loading from objects present at compile time.  The rule for these is if the original object should be a strong root then the inlined field value should be a strong root, if the field is final or otherwise "stable".  If it is mutable, then the JIT may be doing an optimistic optimization that needs a weak root.

Some pointers in code ought to be weak roots, although that does not appear to be the case currently.  Any optimistic optimization based on class might want to unload the optimistically guessed class.  These optimizations include monomorphic inline caches and profile-driven type narrowing.  They might also include user-defined optimizations based on (JSR 292) switchpoints or mutable call sites.

There are lots of "mights" and "shoulds" in the account above.  Making nmethod oops weak, but backed up by constant pool strong roots, "should" work, but it is likely to cause unexpected performance regressions in very dynamic code, due to nmethod invalidation after aggressive deletion of optimistically used data structures.

— John

More information about the hotspot-gc-dev mailing list