Mon, 12 Mar 2012 14:59:00 -0700
7147724: G1: hang in SurrogateLockerThread::manipulatePLL
Summary: Attempting to initiate a marking cycle when allocating a humongous object can, if a marking cycle is successfully initiated by another thread, result in the allocating thread spinning until the marking cycle is complete. Eliminate a deadlock between the main ConcurrentMarkThread, the SurrogateLocker thread, the VM thread, and a mutator thread waiting on the SecondaryFreeList_lock (while free regions are going to become available) by not manipulating the pending list lock during the prologue and epilogue of the cleanup pause.
Reviewed-by: brutisso, jcoomes, tonyp
1 /*
2 * Copyright (c) 2001, 2012, 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 */
25 #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_COLLECTIONSETCHOOSER_HPP
26 #define SHARE_VM_GC_IMPLEMENTATION_G1_COLLECTIONSETCHOOSER_HPP
28 #include "gc_implementation/g1/heapRegion.hpp"
29 #include "utilities/growableArray.hpp"
31 class CSetChooserCache VALUE_OBJ_CLASS_SPEC {
32 private:
33 enum {
34 CacheLength = 16
35 } PrivateConstants;
37 HeapRegion* _cache[CacheLength];
38 int _occupancy; // number of regions in cache
39 int _first; // (index of) "first" region in the cache
41 // adding CacheLength to deal with negative values
42 inline int trim_index(int index) {
43 return (index + CacheLength) % CacheLength;
44 }
46 inline int get_sort_index(int index) {
47 return -index-2;
48 }
49 inline int get_index(int sort_index) {
50 return -sort_index-2;
51 }
53 public:
54 CSetChooserCache(void);
56 inline int occupancy(void) { return _occupancy; }
57 inline bool is_full() { return _occupancy == CacheLength; }
58 inline bool is_empty() { return _occupancy == 0; }
60 void clear(void);
61 void insert(HeapRegion *hr);
62 HeapRegion *remove_first(void);
63 inline HeapRegion *get_first(void) {
64 return _cache[_first];
65 }
67 #ifndef PRODUCT
68 bool verify (void);
69 bool region_in_cache(HeapRegion *hr) {
70 int sort_index = hr->sort_index();
71 if (sort_index < -1) {
72 int index = get_index(sort_index);
73 guarantee(index < CacheLength, "should be within bounds");
74 return _cache[index] == hr;
75 } else
76 return 0;
77 }
78 #endif // PRODUCT
79 };
81 class CollectionSetChooser: public CHeapObj {
83 GrowableArray<HeapRegion*> _markedRegions;
85 // The index of the next candidate old region to be considered for
86 // addition to the CSet.
87 int _curr_index;
89 // The number of candidate old regions added to the CSet chooser.
90 int _length;
92 CSetChooserCache _cache;
93 jint _first_par_unreserved_idx;
95 // If a region has more live bytes than this threshold, it will not
96 // be added to the CSet chooser and will not be a candidate for
97 // collection.
98 size_t _regionLiveThresholdBytes;
100 // The sum of reclaimable bytes over all the regions in the CSet chooser.
101 size_t _remainingReclaimableBytes;
103 public:
105 // Return the current candidate region to be considered for
106 // collection without removing it from the CSet chooser.
107 HeapRegion* peek() {
108 HeapRegion* res = NULL;
109 if (_curr_index < _length) {
110 res = _markedRegions.at(_curr_index);
111 assert(res != NULL,
112 err_msg("Unexpected NULL hr in _markedRegions at index %d",
113 _curr_index));
114 }
115 return res;
116 }
118 // Remove the given region from the CSet chooser and move to the
119 // next one. The given region should be the current candidate region
120 // in the CSet chooser.
121 void remove_and_move_to_next(HeapRegion* hr) {
122 assert(hr != NULL, "pre-condition");
123 assert(_curr_index < _length, "pre-condition");
124 assert(_markedRegions.at(_curr_index) == hr, "pre-condition");
125 hr->set_sort_index(-1);
126 _markedRegions.at_put(_curr_index, NULL);
127 assert(hr->reclaimable_bytes() <= _remainingReclaimableBytes,
128 err_msg("remaining reclaimable bytes inconsistent "
129 "from region: "SIZE_FORMAT" remaining: "SIZE_FORMAT,
130 hr->reclaimable_bytes(), _remainingReclaimableBytes));
131 _remainingReclaimableBytes -= hr->reclaimable_bytes();
132 _curr_index += 1;
133 }
135 CollectionSetChooser();
137 void sortMarkedHeapRegions();
138 void fillCache();
140 // Determine whether to add the given region to the CSet chooser or
141 // not. Currently, we skip humongous regions (we never add them to
142 // the CSet, we only reclaim them during cleanup) and regions whose
143 // live bytes are over the threshold.
144 bool shouldAdd(HeapRegion* hr) {
145 assert(hr->is_marked(), "pre-condition");
146 assert(!hr->is_young(), "should never consider young regions");
147 return !hr->isHumongous() &&
148 hr->live_bytes() < _regionLiveThresholdBytes;
149 }
151 // Calculate the minimum number of old regions we'll add to the CSet
152 // during a mixed GC.
153 size_t calcMinOldCSetLength();
155 // Calculate the maximum number of old regions we'll add to the CSet
156 // during a mixed GC.
157 size_t calcMaxOldCSetLength();
159 // Serial version.
160 void addMarkedHeapRegion(HeapRegion *hr);
162 // Must be called before calls to getParMarkedHeapRegionChunk.
163 // "n_regions" is the number of regions, "chunkSize" the chunk size.
164 void prepareForAddMarkedHeapRegionsPar(size_t n_regions, size_t chunkSize);
165 // Returns the first index in a contiguous chunk of "n_regions" indexes
166 // that the calling thread has reserved. These must be set by the
167 // calling thread using "setMarkedHeapRegion" (to NULL if necessary).
168 jint getParMarkedHeapRegionChunk(jint n_regions);
169 // Set the marked array entry at index to hr. Careful to claim the index
170 // first if in parallel.
171 void setMarkedHeapRegion(jint index, HeapRegion* hr);
172 // Atomically increment the number of added regions by region_num
173 // and the amount of reclaimable bytes by reclaimable_bytes.
174 void updateTotals(jint region_num, size_t reclaimable_bytes);
176 void clearMarkedHeapRegions();
178 // Return the number of candidate regions that remain to be collected.
179 size_t remainingRegions() { return _length - _curr_index; }
181 // Determine whether the CSet chooser has more candidate regions or not.
182 bool isEmpty() { return remainingRegions() == 0; }
184 // Return the reclaimable bytes that remain to be collected on
185 // all the candidate regions in the CSet chooser.
186 size_t remainingReclaimableBytes () { return _remainingReclaimableBytes; }
188 // Returns true if the used portion of "_markedRegions" is properly
189 // sorted, otherwise asserts false.
190 #ifndef PRODUCT
191 bool verify(void);
192 bool regionProperlyOrdered(HeapRegion* r) {
193 int si = r->sort_index();
194 if (si > -1) {
195 guarantee(_curr_index <= si && si < _length,
196 err_msg("curr: %d sort index: %d: length: %d",
197 _curr_index, si, _length));
198 guarantee(_markedRegions.at(si) == r,
199 err_msg("sort index: %d at: "PTR_FORMAT" r: "PTR_FORMAT,
200 si, _markedRegions.at(si), r));
201 } else {
202 guarantee(si == -1, err_msg("sort index: %d", si));
203 }
204 return true;
205 }
206 #endif
208 };
210 #endif // SHARE_VM_GC_IMPLEMENTATION_G1_COLLECTIONSETCHOOSER_HPP