comparison src/share/vm/gc_implementation/g1/g1HotCardCache.cpp @ 10246:194f52aa2f23

7176479: G1: JVM crashes on T5-8 system with 1.5 TB heap Summary: Refactor G1's hot card cache and card counts table into their own files. Simplify the card counts table, including removing the encoding of the card index in each entry. The card counts table now has a 1:1 correspondence with the cards spanned by heap. Space for the card counts table is reserved from virtual memory (rather than C heap) during JVM startup and is committed/expanded when the heap is expanded. Changes were also reviewed-by Vitaly Davidovich. Reviewed-by: tschatzl, jmasa
author johnc
date Thu, 09 May 2013 11:16:39 -0700
parents
children 8847586c9037
comparison
equal deleted inserted replaced
10245:923ac8d1df95 10246:194f52aa2f23
1 /*
2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #include "precompiled.hpp"
26 #include "gc_implementation/g1/dirtyCardQueue.hpp"
27 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
28 #include "gc_implementation/g1/g1HotCardCache.hpp"
29 #include "gc_implementation/g1/g1RemSet.hpp"
30 #include "gc_implementation/g1/heapRegion.hpp"
31 #include "runtime/atomic.hpp"
32
33 G1HotCardCache::G1HotCardCache(G1CollectedHeap *g1h):
34 _g1h(g1h), _hot_cache(NULL), _use_cache(false), _card_counts(g1h) {}
35
36 void G1HotCardCache::initialize() {
37 if (default_use_cache()) {
38 _use_cache = true;
39
40 _hot_cache_size = (1 << G1ConcRSLogCacheSize);
41 _hot_cache = NEW_C_HEAP_ARRAY(jbyte*, _hot_cache_size, mtGC);
42
43 _n_hot = 0;
44 _hot_cache_idx = 0;
45
46 // For refining the cards in the hot cache in parallel
47 int n_workers = (ParallelGCThreads > 0 ?
48 _g1h->workers()->total_workers() : 1);
49 _hot_cache_par_chunk_size = MAX2(1, _hot_cache_size / n_workers);
50 _hot_cache_par_claimed_idx = 0;
51
52 _card_counts.initialize();
53 }
54 }
55
56 G1HotCardCache::~G1HotCardCache() {
57 if (default_use_cache()) {
58 assert(_hot_cache != NULL, "Logic");
59 FREE_C_HEAP_ARRAY(jbyte*, _hot_cache, mtGC);
60 }
61 }
62
63 jbyte* G1HotCardCache::insert(jbyte* card_ptr) {
64 uint count = _card_counts.add_card_count(card_ptr);
65 if (!_card_counts.is_hot(count)) {
66 // The card is not hot so do not store it in the cache;
67 // return it for immediate refining.
68 return card_ptr;
69 }
70
71 // Otherwise, the card is hot.
72 jbyte* res = NULL;
73 MutexLockerEx x(HotCardCache_lock, Mutex::_no_safepoint_check_flag);
74 if (_n_hot == _hot_cache_size) {
75 res = _hot_cache[_hot_cache_idx];
76 _n_hot--;
77 }
78
79 // Now _n_hot < _hot_cache_size, and we can insert at _hot_cache_idx.
80 _hot_cache[_hot_cache_idx] = card_ptr;
81 _hot_cache_idx++;
82
83 if (_hot_cache_idx == _hot_cache_size) {
84 // Wrap around
85 _hot_cache_idx = 0;
86 }
87 _n_hot++;
88
89 return res;
90 }
91
92 void G1HotCardCache::drain(int worker_i,
93 G1RemSet* g1rs,
94 DirtyCardQueue* into_cset_dcq) {
95 if (!default_use_cache()) {
96 assert(_hot_cache == NULL, "Logic");
97 return;
98 }
99
100 assert(_hot_cache != NULL, "Logic");
101 assert(!use_cache(), "cache should be disabled");
102 int start_idx;
103
104 while ((start_idx = _hot_cache_par_claimed_idx) < _n_hot) { // read once
105 int end_idx = start_idx + _hot_cache_par_chunk_size;
106
107 if (start_idx ==
108 Atomic::cmpxchg(end_idx, &_hot_cache_par_claimed_idx, start_idx)) {
109 // The current worker has successfully claimed the chunk [start_idx..end_idx)
110 end_idx = MIN2(end_idx, _n_hot);
111 for (int i = start_idx; i < end_idx; i++) {
112 jbyte* card_ptr = _hot_cache[i];
113 if (card_ptr != NULL) {
114 if (g1rs->refine_card(card_ptr, worker_i, true)) {
115 // The part of the heap spanned by the card contains references
116 // that point into the current collection set.
117 // We need to record the card pointer in the DirtyCardQueueSet
118 // that we use for such cards.
119 //
120 // The only time we care about recording cards that contain
121 // references that point into the collection set is during
122 // RSet updating while within an evacuation pause.
123 // In this case worker_i should be the id of a GC worker thread
124 assert(SafepointSynchronize::is_at_safepoint(), "Should be at a safepoint");
125 assert(worker_i < (int) (ParallelGCThreads == 0 ? 1 : ParallelGCThreads),
126 err_msg("incorrect worker id: "INT32_FORMAT, worker_i));
127
128 into_cset_dcq->enqueue(card_ptr);
129 }
130 }
131 }
132 }
133 }
134 // The existing entries in the hot card cache, which were just refined
135 // above, are discarded prior to re-enabling the cache near the end of the GC.
136 }
137
138 void G1HotCardCache::resize_card_counts(size_t heap_capacity) {
139 _card_counts.resize(heap_capacity);
140 }
141
142 void G1HotCardCache::reset_card_counts(HeapRegion* hr) {
143 _card_counts.clear_region(hr);
144 }
145
146 void G1HotCardCache::reset_card_counts() {
147 _card_counts.clear_all();
148 }