Mercurial > hg > graal-compiler
annotate src/share/vm/gc_implementation/g1/g1StringDedupQueue.cpp @ 20215:983092f35ff7
8028710: G1 does not retire allocation buffers after reference processing work
Summary: G1 does not retire allocation buffers after reference processing work when -XX:+ParallelRefProcEnabled is enabled. This causes wrong calculation of PLAB sizes, as the amount of space wasted is not updated correctly.
Reviewed-by: brutisso
author | tschatzl |
---|---|
date | Mon, 21 Jul 2014 09:40:19 +0200 |
parents | 1772223a25a2 |
children |
rev | line source |
---|---|
17764 | 1 /* |
2 * Copyright (c) 2014, 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 "classfile/javaClasses.hpp" | |
27 #include "gc_implementation/g1/g1StringDedupQueue.hpp" | |
28 #include "memory/gcLocker.hpp" | |
29 #include "runtime/mutexLocker.hpp" | |
30 #include "utilities/stack.inline.hpp" | |
31 | |
32 G1StringDedupQueue* G1StringDedupQueue::_queue = NULL; | |
33 const size_t G1StringDedupQueue::_max_size = 1000000; // Max number of elements per queue | |
34 const size_t G1StringDedupQueue::_max_cache_size = 0; // Max cache size per queue | |
35 | |
36 G1StringDedupQueue::G1StringDedupQueue() : | |
37 _cursor(0), | |
17947
1772223a25a2
8037112: gc/g1/TestHumongousAllocInitialMark.java caused SIGSEGV
pliden
parents:
17764
diff
changeset
|
38 _cancel(false), |
17764 | 39 _empty(true), |
40 _dropped(0) { | |
41 _nqueues = MAX2(ParallelGCThreads, (size_t)1); | |
42 _queues = NEW_C_HEAP_ARRAY(G1StringDedupWorkerQueue, _nqueues, mtGC); | |
43 for (size_t i = 0; i < _nqueues; i++) { | |
44 new (_queues + i) G1StringDedupWorkerQueue(G1StringDedupWorkerQueue::default_segment_size(), _max_cache_size, _max_size); | |
45 } | |
46 } | |
47 | |
48 G1StringDedupQueue::~G1StringDedupQueue() { | |
49 ShouldNotReachHere(); | |
50 } | |
51 | |
52 void G1StringDedupQueue::create() { | |
53 assert(_queue == NULL, "One string deduplication queue allowed"); | |
54 _queue = new G1StringDedupQueue(); | |
55 } | |
56 | |
57 void G1StringDedupQueue::wait() { | |
58 MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag); | |
17947
1772223a25a2
8037112: gc/g1/TestHumongousAllocInitialMark.java caused SIGSEGV
pliden
parents:
17764
diff
changeset
|
59 while (_queue->_empty && !_queue->_cancel) { |
17764 | 60 ml.wait(Mutex::_no_safepoint_check_flag); |
61 } | |
62 } | |
63 | |
17947
1772223a25a2
8037112: gc/g1/TestHumongousAllocInitialMark.java caused SIGSEGV
pliden
parents:
17764
diff
changeset
|
64 void G1StringDedupQueue::cancel_wait() { |
1772223a25a2
8037112: gc/g1/TestHumongousAllocInitialMark.java caused SIGSEGV
pliden
parents:
17764
diff
changeset
|
65 MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag); |
1772223a25a2
8037112: gc/g1/TestHumongousAllocInitialMark.java caused SIGSEGV
pliden
parents:
17764
diff
changeset
|
66 _queue->_cancel = true; |
1772223a25a2
8037112: gc/g1/TestHumongousAllocInitialMark.java caused SIGSEGV
pliden
parents:
17764
diff
changeset
|
67 ml.notify(); |
1772223a25a2
8037112: gc/g1/TestHumongousAllocInitialMark.java caused SIGSEGV
pliden
parents:
17764
diff
changeset
|
68 } |
1772223a25a2
8037112: gc/g1/TestHumongousAllocInitialMark.java caused SIGSEGV
pliden
parents:
17764
diff
changeset
|
69 |
17764 | 70 void G1StringDedupQueue::push(uint worker_id, oop java_string) { |
71 assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint"); | |
72 assert(worker_id < _queue->_nqueues, "Invalid queue"); | |
73 | |
74 // Push and notify waiter | |
75 G1StringDedupWorkerQueue& worker_queue = _queue->_queues[worker_id]; | |
76 if (!worker_queue.is_full()) { | |
77 worker_queue.push(java_string); | |
78 if (_queue->_empty) { | |
79 MonitorLockerEx ml(StringDedupQueue_lock, Mutex::_no_safepoint_check_flag); | |
80 if (_queue->_empty) { | |
81 // Mark non-empty and notify waiter | |
82 _queue->_empty = false; | |
83 ml.notify(); | |
84 } | |
85 } | |
86 } else { | |
87 // Queue is full, drop the string and update the statistics | |
88 Atomic::inc_ptr(&_queue->_dropped); | |
89 } | |
90 } | |
91 | |
92 oop G1StringDedupQueue::pop() { | |
93 assert(!SafepointSynchronize::is_at_safepoint(), "Must not be at safepoint"); | |
94 No_Safepoint_Verifier nsv; | |
95 | |
96 // Try all queues before giving up | |
97 for (size_t tries = 0; tries < _queue->_nqueues; tries++) { | |
98 // The cursor indicates where we left of last time | |
99 G1StringDedupWorkerQueue* queue = &_queue->_queues[_queue->_cursor]; | |
100 while (!queue->is_empty()) { | |
101 oop obj = queue->pop(); | |
102 // The oop we pop can be NULL if it was marked | |
103 // dead. Just ignore those and pop the next oop. | |
104 if (obj != NULL) { | |
105 return obj; | |
106 } | |
107 } | |
108 | |
109 // Try next queue | |
110 _queue->_cursor = (_queue->_cursor + 1) % _queue->_nqueues; | |
111 } | |
112 | |
113 // Mark empty | |
114 _queue->_empty = true; | |
115 | |
116 return NULL; | |
117 } | |
118 | |
119 void G1StringDedupQueue::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl) { | |
120 // A worker thread first claims a queue, which ensures exclusive | |
121 // access to that queue, then continues to process it. | |
122 for (;;) { | |
123 // Grab next queue to scan | |
124 size_t queue = cl->claim_queue(); | |
125 if (queue >= _queue->_nqueues) { | |
126 // End of queues | |
127 break; | |
128 } | |
129 | |
130 // Scan the queue | |
131 unlink_or_oops_do(cl, queue); | |
132 } | |
133 } | |
134 | |
135 void G1StringDedupQueue::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, size_t queue) { | |
136 assert(queue < _queue->_nqueues, "Invalid queue"); | |
137 StackIterator<oop, mtGC> iter(_queue->_queues[queue]); | |
138 while (!iter.is_empty()) { | |
139 oop* p = iter.next_addr(); | |
140 if (*p != NULL) { | |
141 if (cl->is_alive(*p)) { | |
142 cl->keep_alive(p); | |
143 } else { | |
144 // Clear dead reference | |
145 *p = NULL; | |
146 } | |
147 } | |
148 } | |
149 } | |
150 | |
151 void G1StringDedupQueue::print_statistics(outputStream* st) { | |
152 st->print_cr( | |
153 " [Queue]\n" | |
154 " [Dropped: "UINTX_FORMAT"]", _queue->_dropped); | |
155 } | |
156 | |
157 void G1StringDedupQueue::verify() { | |
158 for (size_t i = 0; i < _queue->_nqueues; i++) { | |
159 StackIterator<oop, mtGC> iter(_queue->_queues[i]); | |
160 while (!iter.is_empty()) { | |
161 oop obj = iter.next(); | |
162 if (obj != NULL) { | |
163 guarantee(Universe::heap()->is_in_reserved(obj), "Object must be on the heap"); | |
164 guarantee(!obj->is_forwarded(), "Object must not be forwarded"); | |
165 guarantee(java_lang_String::is_instance(obj), "Object must be a String"); | |
166 } | |
167 } | |
168 } | |
169 } |