hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp
bool G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i,
bool check_for_refs_into_cset) {
{- -------------------------------------------
(1) (ここに来た時点では) もう dirty でなかった場合, することは何もない, ここでリターン.
---------------------------------------- -}
// If the card is no longer dirty, nothing to do.
if (*card_ptr != CardTableModRefBS::dirty_card_val()) {
// No need to return that this card contains refs that point
// into the collection set.
return false;
}
{- -------------------------------------------
(1) 処理対象の card に対応する HeapRegion を取得する(以下の r).
(見つからなければ, ここでリターン)
(どういうケース?? #TODO)
---------------------------------------- -}
// Construct the region representing the card.
HeapWord* start = _ct_bs->addr_for(card_ptr);
// And find the region containing it.
HeapRegion* r = _g1->heap_region_containing(start);
if (r == NULL) {
guarantee(_g1->is_in_permanent(start), "Or else where?");
// Again no need to return that this card contains refs that
// point into the collection set.
return false; // Not in the G1 heap (might be in perm, for example.)
}
{- -------------------------------------------
(1) Young な HeapRegion であれば, 処理する必要は無いので(?), ここでリターン.
(<= Remembered Set は処理対象じゃない領域用のものだから, そもそも処理対象なら要らないか?? #TODO)
---------------------------------------- -}
// Why do we have to check here whether a card is on a young region,
// given that we dirty young regions and, as a result, the
// post-barrier is supposed to filter them out and never to enqueue
// them? When we allocate a new region as the "allocation region" we
// actually dirty its cards after we release the lock, since card
// dirtying while holding the lock was a performance bottleneck. So,
// as a result, it is possible for other threads to actually
// allocate objects in the region (after the acquire the lock)
// before all the cards on the region are dirtied. This is unlikely,
// and it doesn't happen often, but it can happen. So, the extra
// check below filters out those cards.
if (r->is_young()) {
return false;
}
{- -------------------------------------------
(1) Collection Set に選ばれている HeapRegion であれば, 処理する必要は無いので(?), ここでリターン.
(<= Remembered Set は処理対象じゃない領域用のものだから, そもそも処理対象なら要らないか?? #TODO)
---------------------------------------- -}
// While we are processing RSet buffers during the collection, we
// actually don't want to scan any cards on the collection set,
// since we don't want to update remebered sets with entries that
// point into the collection set, given that live objects from the
// collection set are about to move and such entries will be stale
// very soon. This change also deals with a reliability issue which
// involves scanning a card in the collection set and coming across
// an array that was being chunked and looking malformed. Note,
// however, that if evacuation fails, we have to scan any objects
// that were not moved and create any missing entries.
if (r->in_collection_set()) {
return false;
}
{- -------------------------------------------
(1) (以下の処理で, まず遅延処理するかどうかを判定する. ...#TODO)
---------------------------------------- -}
// Should we defer processing the card?
//
// Previously the result from the insert_cache call would be
// either card_ptr (implying that card_ptr was currently "cold"),
// null (meaning we had inserted the card ptr into the "hot"
// cache, which had some headroom), or a "hot" card ptr
// extracted from the "hot" cache.
//
// Now that the _card_counts cache in the ConcurrentG1Refine
// instance is an evicting hash table, the result we get back
// could be from evicting the card ptr in an already occupied
// bucket (in which case we have replaced the card ptr in the
// bucket with card_ptr and "defer" is set to false). To avoid
// having a data structure (updates to which would need a lock)
// to hold these unprocessed dirty cards, we need to immediately
// process card_ptr. The actions needed to be taken on return
// from cache_insert are summarized in the following table:
//
// res defer action
// --------------------------------------------------------------
// null false card evicted from _card_counts & replaced with
// card_ptr; evicted ptr added to hot cache.
// No need to process res; immediately process card_ptr
//
// null true card not evicted from _card_counts; card_ptr added
// to hot cache.
// Nothing to do.
//
// non-null false card evicted from _card_counts & replaced with
// card_ptr; evicted ptr is currently "cold" or
// caused an eviction from the hot cache.
// Immediately process res; process card_ptr.
//
// non-null true card not evicted from _card_counts; card_ptr is
// currently cold, or caused an eviction from hot
// cache.
// Immediately process res; no need to process card_ptr.
{- -------------------------------------------
(1.1) (変数宣言など)
---------------------------------------- -}
jbyte* res = card_ptr;
bool defer = false;
// This gets set to true if the card being refined has references
// that point into the collection set.
bool oops_into_cset = false;
{- -------------------------------------------
(1.1) cache_insert() でキャッシュに突っ込み, ついでに defer するかどうか判定する(?? #TODO)
...
---------------------------------------- -}
if (_cg1r->use_cache()) {
jbyte* res = _cg1r->cache_insert(card_ptr, &defer);
if (res != NULL && (res != card_ptr || defer)) {
start = _ct_bs->addr_for(res);
r = _g1->heap_region_containing(start);
if (r == NULL) {
assert(_g1->is_in_permanent(start), "Or else where?");
} else {
// Checking whether the region we got back from the cache
// is young here is inappropriate. The region could have been
// freed, reallocated and tagged as young while in the cache.
// Hence we could see its young type change at any time.
//
// Process card pointer we get back from the hot card cache. This
// will check whether the region containing the card is young
// _after_ checking that the region has been allocated from.
oops_into_cset = concurrentRefineOneCard_impl(res, worker_i,
false /* check_for_refs_into_cset */);
// The above call to concurrentRefineOneCard_impl is only
// performed if the hot card cache is enabled. This cache is
// disabled during an evacuation pause - which is the only
// time when we need know if the card contains references
// that point into the collection set. Also when the hot card
// cache is enabled, this code is executed by the concurrent
// refine threads - rather than the GC worker threads - and
// concurrentRefineOneCard_impl will return false.
assert(!oops_into_cset, "should not see true here");
}
}
}
{- -------------------------------------------
(1.1) (以下は遅延処理しない場合(= この場で処理する場合) の処理)
G1RemSet::concurrentRefineOneCard_impl() を呼んで処理を行う.
---------------------------------------- -}
if (!defer) {
oops_into_cset =
concurrentRefineOneCard_impl(card_ptr, worker_i, check_for_refs_into_cset);
// We should only be detecting that the card contains references
// that point into the collection set if the current thread is
// a GC worker thread.
assert(!oops_into_cset || SafepointSynchronize::is_at_safepoint(),
"invalid result at non safepoint");
}
{- -------------------------------------------
(1)
---------------------------------------- -}
return oops_into_cset;
}
This document is available under the GNU GENERAL PUBLIC LICENSE Version 2.