g1RemSet.cpp revision 2943
5693N/A * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. 5693N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5693N/A * This code is free software; you can redistribute it and/or modify it 5693N/A * under the terms of the GNU General Public License version 2 only, as 5693N/A * published by the Free Software Foundation. 5693N/A * This code is distributed in the hope that it will be useful, but WITHOUT 5693N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 5693N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 5693N/A * version 2 for more details (a copy is included in the LICENSE file that 5693N/A * You should have received a copy of the GNU General Public License version 5693N/A * 2 along with this work; if not, write to the Free Software Foundation, 5693N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 5693N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 5693N/A // Stack allocate the DirtyCardToOopClosure instance 5693N/A // Set the "from" region in the closure. 5693N/A // We make the card as "claimed" lazily (so races are possible 5693N/A // but they're benign), which reduces the number of duplicate 5693N/A // scans (the rsets of the regions in the cset can intersect). 5693N/A // If we ever free the collection set concurrently, we should also 5693N/A // clear the card table concurrently therefore we won't need to 5693N/A // add regions of the collection set to the dirty cards region. 5693N/A // If we didn't return above, then 5693N/A // _try_claimed || r->claim_iter() 5693N/A // is true: either we're supposed to work on claimed-but-not-complete 5693N/A // regions, or we successfully claimed the region. 5693N/A // We claim cards in block so as to recude the contention. The block size is determined by 5693N/A // the G1RSetScanBlockSize parameter. 5693N/A // If the card is dirty, then we will scan it during updateRS. // Closure used for updating RSets and recording references that // point into the collection set. Only called during an // The only time we care about recording cards that // contain references that point into the collection set // is during RSet updating within an evacuation pause. // In this case worker_i should be the id of a GC worker thread. // 'card_ptr' contains references that point into the collection // set. We need to record the card in the DCQS // (G1CollectedHeap::into_cset_dirty_card_queue_set()) // that's used for that purpose. // Apply the given closure to all remaining log entries. // Now there should be no dirty cards. // XXX This isn't true any more: keeping cards of young regions // marked dirty broke it. Need some reasonable fix. for (
int i = 0; i < N; i++)
_histo[i] = 0;
// Fit it into a histo bin. for (
int i =
1; i <
mx-
1; i++) {
(
1 << (
MIN + i -
1)) +
1,
// Make this into a command-line flag... // We cache the value of 'oc' closure into the appropriate slot in the // _cset_rs_update_cl for this worker // A DirtyCardQueue that is used to hold cards containing references // that point into the collection set. This DCQ is associated with a // circumstances (i.e. the pause successfully completes), these cards // are just discarded (there's no need to update the RSets of regions // that were in the collection set - after the pause these regions // are wholly 'free' of live objects. In the event of an evacuation // * passed to the DirtyCardQueueSet that is used to manage deferred // * scanned for references that point into the collection set // and the RSet of the corresponding region in the collection set // is updated immediately. // The two flags below were introduced temporarily to serialize // the updating and scanning of remembered sets. There are some // race conditions when these two operations are done in parallel // and they are causing failures. When we resolve said race // conditions, we'll revert back to parallel remembered set // updating and scanning. See CRs 6677707 and 6677708. // We now clear the cached values of _cset_rs_update_cl for this worker // Don't set the number of workers here. It will be set // _seq_task->set_n_termination((int)n_workers()); // This closure, applied to a DirtyCardQueueSet, is used to immediately // update the RSets for the regions in the CSet. For each card it iterates // through the oops which coincide with that card. It scans the reference // fields in each oop; when it finds an oop that points into the collection // set, the RSet for the region containing the referenced object is updated. // Construct the region representing the card. // And find the region containing it. // Scan oops in the card looking for references into the collection set // We can pass false as the "filter_young" parameter here as: // * we should be in a STW pause, // * the DCQS to which this closure is applied is used to hold // references that point into the collection set from the prior // * the post-write barrier shouldn't be logging updates to young // regions (but there is a situation where this can happen - see // the comment in G1RemSet::concurrentRefineOneCard below - // that should not be applicable here), and // * during actual RSet updating, the filtering of cards in young // regions in HeapRegion::oops_on_card_seq_iterate_careful is // As a result, when this closure is applied to "refs into cset" // DCQS, we shouldn't see any cards in young regions. false /* filter_young */,
// Since this is performed in the event of an evacuation failure, we // we shouldn't see a non-null stop point // Set all cards back to clean. // Restore remembered sets for the regions pointing into the collection set. // If deferred RS updates are enabled then we just need to transfer // the completed buffers from (a) the DirtyCardQueueSet used to hold // cards that contain references that point into the collection set // to (b) the DCQS used to hold the deferred RS updates // Free any completed buffers in the DirtyCardQueueSet used to hold cards // which contain references that point into the collection. "all buffers should be freed");
// Construct the region representing the card. // And find the region containing it. // ConcurrentG1RefineThreads have worker numbers larger than what // _cset_rs_update_cl[] is set up to handle. But those threads should // only be active outside of a collection which means that when they // reach here they should have check_for_refs_into_cset == false. // The region for the current card may be a young region. The // current card may have been a card that was evicted from the // card cache. When the card was inserted into the cache, we had // determined that its region was non-young. While in the cache, // the region may have been freed during a cleanup pause, reallocated // We wish to filter out cards for such a region but the current // thread, if we're running concurrently, may "see" the young type // change at any time (so an earlier "is_young" check may pass or // fail arbitrarily). We tell the iteration code to perform this // filtering when it has been determined that there has been an actual // allocation in this region and making it safe to check the young type. // If stop_point is non-null, then we encountered an unallocated region // (perhaps the unfilled portion of a TLAB.) For now, we'll dirty the // card and re-enqueue: if we put off the card until a GC pause, then the // unallocated portion will be filled in. Alternatively, we might try // the full complexity of the technique used in "regular" precleaning. // The card might have gotten re-dirtied and re-enqueued while we // worked. (In fact, it's pretty likely.) // If the card is no longer dirty, nothing to do. // No need to return that this card contains refs that point // into the collection set. // Construct the region representing the card. // And find the region containing it. // 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.) // 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. // 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. // 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: // -------------------------------------------------------------- // 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 // 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 // Immediately process res; no need to process card_ptr. // This gets set to true if the card being refined has references // that point into the collection set. // 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. 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. // We should only be detecting that the card contains references // that point into the collection set if the current thread is "invalid result at non safepoint");