JDK-8027551 : Add fast path checking whether an object is scavengable in g1 oop scan closures
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: gc
  • Affected Version: hs25,8
  • Priority: P3
  • Status: Closed
  • Resolution: Won't Fix
  • Submitted: 2013-10-30
  • Updated: 2020-05-18
  • Resolved: 2020-05-18
Related Reports
Relates :  
Description
At the moment G1 scan closures use the standard devirtualization mechanism implemented in Hotspot; for every reference location the do_oop_work_nv method is finally called.

It would be faster to, similar to other collectors, split out the check whether the reference is actually going to be scavenged first, and only then call do_oop_work_nv.

E.g. in parallel scavenge, instanceKlass.cpp:

void InstanceKlass::oop_push_contents(PSPromotionManager* pm, oop obj) {
  InstanceKlass_OOP_MAP_REVERSE_ITERATE( \
    obj, \
    if (PSScavenge::should_scavenge(p)) { \  // <--- fast path check whether there is a point to do the work or not
      pm->claim_or_forward_depth(p); \   // <--- push reference
    }, \
    assert_nothing )
}

This fast-path check is small and likely to be inlined (as opposed to the full do_oop_work_nv method, allowing quick removal of doing unnecessary work for references the collector is not interested in.

In case of G1, this check can be done (relatively) quickly using the _in_cset_fast_test array of G1CollectedHeap.

Comments
The oop iteration framework has been changed so much that this suggestion does not apply any more. In fact, there is no such optimization any more for non-G1 collectors. The change in the oop iteration framework also did not show regressions, so the impact of such a change is likely negligible too.
18-05-2020

This is more an investigation at this time than an actual bug fix. The suggestions above work, but they do not seem to really affect performance. More thorough changes may be needed to get benefit.
28-10-2015

In G1 the only generic check you can do here is a NULL check; the problem is that in G1, created Old->Old gen references need rset update, so a blanket should_scavenge() that only checks the source region (ie. young) is not enough. G1 also needs to update these created Old->Old references. There are two options here, either make the check more complicated (e.g. is_in_cset(p) || crosses_regions(p, obj) I think, may be wrong), or specialize the scan closures on the from-region type with from-region type specific work queues. I.e. for objects that are in survivor we do not need to do any rset update stuff, so is_in_cset(p) would be sufficient as should_scavenge() equivalent, and just take the perf hit for calling the method when looking at objects from old gen. Could be coupled with specialized scan closures depending on source region type.
02-11-2013

Implementation wise either some equivalent of the PSPromotionManager, or just passing the G1ParScanState (similar to PSPromotionManager) closures might be useful.
30-10-2013