13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26 #include "precompiled.hpp"
27 #include "gc/shenandoah/shenandoahCollectorPolicy.hpp"
28 #include "gc/shenandoah/shenandoahConcurrentGC.hpp"
29 #include "gc/shenandoah/shenandoahControlThread.hpp"
30 #include "gc/shenandoah/shenandoahDegeneratedGC.hpp"
31 #include "gc/shenandoah/shenandoahFreeSet.hpp"
32 #include "gc/shenandoah/shenandoahFullGC.hpp"
33 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
34 #include "gc/shenandoah/shenandoahMonitoringSupport.hpp"
35 #include "gc/shenandoah/shenandoahPacer.inline.hpp"
36 #include "gc/shenandoah/shenandoahUtils.hpp"
37 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
38 #include "gc/shenandoah/mode/shenandoahMode.hpp"
39 #include "logging/log.hpp"
40 #include "memory/metaspaceUtils.hpp"
41 #include "memory/metaspaceStats.hpp"
42
43 ShenandoahControlThread::ShenandoahControlThread() :
44 ShenandoahController(),
45 _requested_gc_cause(GCCause::_no_cause_specified),
46 _degen_point(ShenandoahGC::_degenerated_outside_cycle) {
47 set_name("Shenandoah Control Thread");
48 create_and_start();
49 }
50
51 void ShenandoahControlThread::run_service() {
52 ShenandoahHeap* const heap = ShenandoahHeap::heap();
68 ShenandoahHeuristics* const heuristics = heap->heuristics();
69 while (!in_graceful_shutdown() && !should_terminate()) {
70 // Figure out if we have pending requests.
71 const bool alloc_failure_pending = _alloc_failure_gc.is_set();
72 const bool is_gc_requested = _gc_requested.is_set();
73 const GCCause::Cause requested_gc_cause = _requested_gc_cause;
74
75 // This control loop iteration has seen this much allocation.
76 const size_t allocs_seen = reset_allocs_seen();
77
78 // Check if we have seen a new target for soft max heap size.
79 const bool soft_max_changed = heap->check_soft_max_changed();
80
81 // Choose which GC mode to run in. The block below should select a single mode.
82 GCMode mode = none;
83 GCCause::Cause cause = GCCause::_last_gc_cause;
84 ShenandoahGC::ShenandoahDegenPoint degen_point = ShenandoahGC::_degenerated_unset;
85
86 if (alloc_failure_pending) {
87 // Allocation failure takes precedence: we have to deal with it first thing
88 log_info(gc)("Trigger: Handle Allocation Failure");
89
90 cause = GCCause::_allocation_failure;
91
92 // Consume the degen point, and seed it with default value
93 degen_point = _degen_point;
94 _degen_point = ShenandoahGC::_degenerated_outside_cycle;
95
96 if (ShenandoahDegeneratedGC && heuristics->should_degenerate_cycle()) {
97 heuristics->record_allocation_failure_gc();
98 policy->record_alloc_failure_to_degenerated(degen_point);
99 mode = stw_degenerated;
100 } else {
101 heuristics->record_allocation_failure_gc();
102 policy->record_alloc_failure_to_full();
103 mode = stw_full;
104 }
105 } else if (is_gc_requested) {
106 cause = requested_gc_cause;
107 log_info(gc)("Trigger: GC request (%s)", GCCause::to_string(cause));
108 heuristics->record_requested_gc();
109
110 if (ShenandoahCollectorPolicy::should_run_full_gc(cause)) {
111 mode = stw_full;
112 } else {
113 mode = default_mode;
114 // Unload and clean up everything
115 heap->set_unload_classes(heuristics->can_unload_classes());
116 }
117 } else {
118 // Potential normal cycle: ask heuristics if it wants to act
119 if (heuristics->should_start_gc()) {
120 mode = default_mode;
121 cause = default_cause;
122 }
123
124 // Ask policy if this cycle wants to process references or unload classes
125 heap->set_unload_classes(heuristics->should_unload_classes());
126 }
127
298 // | (af) | (af) | (af) |
299 // ..................|....................|.................|..............|.......................
300 // | | | |
301 // | | | | Degenerated GC
302 // v v v |
303 // STW Mark ----------> STW Evac ----> STW Update-Refs ----->o
304 // | | | ^
305 // | (af) | (af) | (af) |
306 // ..................|....................|.................|..............|.......................
307 // | | | |
308 // | v | | Full GC
309 // \------------------->o<----------------/ |
310 // | |
311 // v |
312 // Full GC --------------------------/
313 //
314 ShenandoahHeap* heap = ShenandoahHeap::heap();
315 if (check_cancellation_or_degen(ShenandoahGC::_degenerated_outside_cycle)) return;
316
317 GCIdMark gc_id_mark;
318 ShenandoahGCSession session(cause);
319
320 TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
321
322 ShenandoahConcurrentGC gc;
323 if (gc.collect(cause)) {
324 // Cycle is complete. There were no failed allocation requests and no degeneration, so count this as good progress.
325 heap->notify_gc_progress();
326 heap->heuristics()->record_success_concurrent();
327 heap->shenandoah_policy()->record_success_concurrent(gc.abbreviated());
328 } else {
329 assert(heap->cancelled_gc(), "Must have been cancelled");
330 check_cancellation_or_degen(gc.degen_point());
331 }
332 }
333
334 bool ShenandoahControlThread::check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point) {
335 ShenandoahHeap* heap = ShenandoahHeap::heap();
336 if (heap->cancelled_gc()) {
337 assert (is_alloc_failure_gc() || in_graceful_shutdown(), "Cancel GC either for alloc failure GC, or gracefully exiting");
338 if (!in_graceful_shutdown()) {
339 assert (_degen_point == ShenandoahGC::_degenerated_outside_cycle,
340 "Should not be set yet: %s", ShenandoahGC::degen_point_to_string(_degen_point));
341 _degen_point = point;
342 }
343 return true;
344 }
345 return false;
346 }
347
348 void ShenandoahControlThread::stop_service() {
349 // Nothing to do here.
350 }
351
352 void ShenandoahControlThread::service_stw_full_cycle(GCCause::Cause cause) {
353 GCIdMark gc_id_mark;
354 ShenandoahGCSession session(cause);
355
356 ShenandoahFullGC gc;
357 gc.collect(cause);
358 }
359
360 void ShenandoahControlThread::service_stw_degenerated_cycle(GCCause::Cause cause, ShenandoahGC::ShenandoahDegenPoint point) {
361 assert (point != ShenandoahGC::_degenerated_unset, "Degenerated point should be set");
362
363 GCIdMark gc_id_mark;
364 ShenandoahGCSession session(cause);
365
366 ShenandoahDegenGC gc(point);
367 gc.collect(cause);
368 }
369
370 void ShenandoahControlThread::request_gc(GCCause::Cause cause) {
371 if (ShenandoahCollectorPolicy::should_handle_requested_gc(cause)) {
372 handle_requested_gc(cause);
373 }
374 }
375
376 void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) {
377 // For normal requested GCs (System.gc) we want to block the caller. However,
378 // for whitebox requested GC, we want to initiate the GC and return immediately.
379 // The whitebox caller thread will arrange for itself to wait until the GC notifies
380 // it that has reached the requested breakpoint (phase in the GC).
381 if (cause == GCCause::_wb_breakpoint) {
382 _requested_gc_cause = cause;
383 _gc_requested.set();
384 return;
385 }
386
|
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26 #include "precompiled.hpp"
27 #include "gc/shenandoah/shenandoahCollectorPolicy.hpp"
28 #include "gc/shenandoah/shenandoahConcurrentGC.hpp"
29 #include "gc/shenandoah/shenandoahControlThread.hpp"
30 #include "gc/shenandoah/shenandoahDegeneratedGC.hpp"
31 #include "gc/shenandoah/shenandoahFreeSet.hpp"
32 #include "gc/shenandoah/shenandoahFullGC.hpp"
33 #include "gc/shenandoah/shenandoahGeneration.hpp"
34 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
35 #include "gc/shenandoah/shenandoahMonitoringSupport.hpp"
36 #include "gc/shenandoah/shenandoahPacer.inline.hpp"
37 #include "gc/shenandoah/shenandoahUtils.hpp"
38 #include "gc/shenandoah/heuristics/shenandoahHeuristics.hpp"
39 #include "gc/shenandoah/mode/shenandoahMode.hpp"
40 #include "logging/log.hpp"
41 #include "memory/metaspaceUtils.hpp"
42 #include "memory/metaspaceStats.hpp"
43
44 ShenandoahControlThread::ShenandoahControlThread() :
45 ShenandoahController(),
46 _requested_gc_cause(GCCause::_no_cause_specified),
47 _degen_point(ShenandoahGC::_degenerated_outside_cycle) {
48 set_name("Shenandoah Control Thread");
49 create_and_start();
50 }
51
52 void ShenandoahControlThread::run_service() {
53 ShenandoahHeap* const heap = ShenandoahHeap::heap();
69 ShenandoahHeuristics* const heuristics = heap->heuristics();
70 while (!in_graceful_shutdown() && !should_terminate()) {
71 // Figure out if we have pending requests.
72 const bool alloc_failure_pending = _alloc_failure_gc.is_set();
73 const bool is_gc_requested = _gc_requested.is_set();
74 const GCCause::Cause requested_gc_cause = _requested_gc_cause;
75
76 // This control loop iteration has seen this much allocation.
77 const size_t allocs_seen = reset_allocs_seen();
78
79 // Check if we have seen a new target for soft max heap size.
80 const bool soft_max_changed = heap->check_soft_max_changed();
81
82 // Choose which GC mode to run in. The block below should select a single mode.
83 GCMode mode = none;
84 GCCause::Cause cause = GCCause::_last_gc_cause;
85 ShenandoahGC::ShenandoahDegenPoint degen_point = ShenandoahGC::_degenerated_unset;
86
87 if (alloc_failure_pending) {
88 // Allocation failure takes precedence: we have to deal with it first thing
89 heuristics->log_trigger("Handle Allocation Failure");
90
91 cause = GCCause::_allocation_failure;
92
93 // Consume the degen point, and seed it with default value
94 degen_point = _degen_point;
95 _degen_point = ShenandoahGC::_degenerated_outside_cycle;
96
97 if (ShenandoahDegeneratedGC && heuristics->should_degenerate_cycle()) {
98 heuristics->record_allocation_failure_gc();
99 policy->record_alloc_failure_to_degenerated(degen_point);
100 mode = stw_degenerated;
101 } else {
102 heuristics->record_allocation_failure_gc();
103 policy->record_alloc_failure_to_full();
104 mode = stw_full;
105 }
106 } else if (is_gc_requested) {
107 cause = requested_gc_cause;
108 heuristics->log_trigger("GC request (%s)", GCCause::to_string(cause));
109 heuristics->record_requested_gc();
110
111 if (ShenandoahCollectorPolicy::should_run_full_gc(cause)) {
112 mode = stw_full;
113 } else {
114 mode = default_mode;
115 // Unload and clean up everything
116 heap->set_unload_classes(heuristics->can_unload_classes());
117 }
118 } else {
119 // Potential normal cycle: ask heuristics if it wants to act
120 if (heuristics->should_start_gc()) {
121 mode = default_mode;
122 cause = default_cause;
123 }
124
125 // Ask policy if this cycle wants to process references or unload classes
126 heap->set_unload_classes(heuristics->should_unload_classes());
127 }
128
299 // | (af) | (af) | (af) |
300 // ..................|....................|.................|..............|.......................
301 // | | | |
302 // | | | | Degenerated GC
303 // v v v |
304 // STW Mark ----------> STW Evac ----> STW Update-Refs ----->o
305 // | | | ^
306 // | (af) | (af) | (af) |
307 // ..................|....................|.................|..............|.......................
308 // | | | |
309 // | v | | Full GC
310 // \------------------->o<----------------/ |
311 // | |
312 // v |
313 // Full GC --------------------------/
314 //
315 ShenandoahHeap* heap = ShenandoahHeap::heap();
316 if (check_cancellation_or_degen(ShenandoahGC::_degenerated_outside_cycle)) return;
317
318 GCIdMark gc_id_mark;
319 ShenandoahGCSession session(cause, heap->global_generation());
320
321 TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters());
322
323 ShenandoahConcurrentGC gc(heap->global_generation(), false);
324 if (gc.collect(cause)) {
325 // Cycle is complete. There were no failed allocation requests and no degeneration, so count this as good progress.
326 heap->notify_gc_progress();
327 heap->global_generation()->heuristics()->record_success_concurrent();
328 heap->shenandoah_policy()->record_success_concurrent(false, gc.abbreviated());
329 heap->log_heap_status("At end of GC");
330 } else {
331 assert(heap->cancelled_gc(), "Must have been cancelled");
332 check_cancellation_or_degen(gc.degen_point());
333 heap->log_heap_status("At end of cancelled GC");
334 }
335 }
336
337 bool ShenandoahControlThread::check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point) {
338 ShenandoahHeap* heap = ShenandoahHeap::heap();
339 if (heap->cancelled_gc()) {
340 assert (is_alloc_failure_gc() || in_graceful_shutdown(), "Cancel GC either for alloc failure GC, or gracefully exiting");
341 if (!in_graceful_shutdown()) {
342 assert (_degen_point == ShenandoahGC::_degenerated_outside_cycle,
343 "Should not be set yet: %s", ShenandoahGC::degen_point_to_string(_degen_point));
344 _degen_point = point;
345 }
346 return true;
347 }
348 return false;
349 }
350
351 void ShenandoahControlThread::stop_service() {
352 // Nothing to do here.
353 }
354
355 void ShenandoahControlThread::service_stw_full_cycle(GCCause::Cause cause) {
356 ShenandoahHeap* const heap = ShenandoahHeap::heap();
357 GCIdMark gc_id_mark;
358 ShenandoahGCSession session(cause, heap->global_generation());
359
360 ShenandoahFullGC gc;
361 gc.collect(cause);
362 }
363
364 void ShenandoahControlThread::service_stw_degenerated_cycle(GCCause::Cause cause, ShenandoahGC::ShenandoahDegenPoint point) {
365 assert (point != ShenandoahGC::_degenerated_unset, "Degenerated point should be set");
366 ShenandoahHeap* const heap = ShenandoahHeap::heap();
367 GCIdMark gc_id_mark;
368 ShenandoahGCSession session(cause, heap->global_generation());
369
370 ShenandoahDegenGC gc(point, heap->global_generation());
371 gc.collect(cause);
372 }
373
374 void ShenandoahControlThread::request_gc(GCCause::Cause cause) {
375 if (ShenandoahCollectorPolicy::should_handle_requested_gc(cause)) {
376 handle_requested_gc(cause);
377 }
378 }
379
380 void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) {
381 // For normal requested GCs (System.gc) we want to block the caller. However,
382 // for whitebox requested GC, we want to initiate the GC and return immediately.
383 // The whitebox caller thread will arrange for itself to wait until the GC notifies
384 // it that has reached the requested breakpoint (phase in the GC).
385 if (cause == GCCause::_wb_breakpoint) {
386 _requested_gc_cause = cause;
387 _gc_requested.set();
388 return;
389 }
390
|