1 /* |
1 /* |
2 * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. |
7 * published by the Free Software Foundation. |
23 */ |
23 */ |
24 |
24 |
25 #include "precompiled.hpp" |
25 #include "precompiled.hpp" |
26 #include "gc/g1/g1CollectedHeap.inline.hpp" |
26 #include "gc/g1/g1CollectedHeap.inline.hpp" |
27 #include "gc/g1/g1CollectionSet.hpp" |
27 #include "gc/g1/g1CollectionSet.hpp" |
|
28 #include "gc/g1/g1CollectionSetCandidates.hpp" |
28 #include "gc/g1/g1CollectorState.hpp" |
29 #include "gc/g1/g1CollectorState.hpp" |
29 #include "gc/g1/g1ParScanThreadState.hpp" |
30 #include "gc/g1/g1ParScanThreadState.hpp" |
30 #include "gc/g1/g1Policy.hpp" |
31 #include "gc/g1/g1Policy.hpp" |
31 #include "gc/g1/heapRegion.inline.hpp" |
32 #include "gc/g1/heapRegion.inline.hpp" |
32 #include "gc/g1/heapRegionRemSet.hpp" |
33 #include "gc/g1/heapRegionRemSet.hpp" |
42 |
43 |
43 G1GCPhaseTimes* G1CollectionSet::phase_times() { |
44 G1GCPhaseTimes* G1CollectionSet::phase_times() { |
44 return _policy->phase_times(); |
45 return _policy->phase_times(); |
45 } |
46 } |
46 |
47 |
47 CollectionSetChooser* G1CollectionSet::cset_chooser() { |
|
48 return _cset_chooser; |
|
49 } |
|
50 |
|
51 double G1CollectionSet::predict_region_elapsed_time_ms(HeapRegion* hr) { |
48 double G1CollectionSet::predict_region_elapsed_time_ms(HeapRegion* hr) { |
52 return _policy->predict_region_elapsed_time_ms(hr, collector_state()->in_young_only_phase()); |
49 return _policy->predict_region_elapsed_time_ms(hr, collector_state()->in_young_only_phase()); |
53 } |
50 } |
54 |
51 |
55 G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy) : |
52 G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy) : |
56 _g1h(g1h), |
53 _g1h(g1h), |
57 _policy(policy), |
54 _policy(policy), |
58 _cset_chooser(new CollectionSetChooser()), |
55 _candidates(NULL), |
59 _eden_region_length(0), |
56 _eden_region_length(0), |
60 _survivor_region_length(0), |
57 _survivor_region_length(0), |
61 _old_region_length(0), |
58 _old_region_length(0), |
62 _collection_set_regions(NULL), |
59 _collection_set_regions(NULL), |
63 _collection_set_cur_length(0), |
60 _collection_set_cur_length(0), |
78 G1CollectionSet::~G1CollectionSet() { |
75 G1CollectionSet::~G1CollectionSet() { |
79 if (_collection_set_regions != NULL) { |
76 if (_collection_set_regions != NULL) { |
80 FREE_C_HEAP_ARRAY(uint, _collection_set_regions); |
77 FREE_C_HEAP_ARRAY(uint, _collection_set_regions); |
81 } |
78 } |
82 free_optional_regions(); |
79 free_optional_regions(); |
83 delete _cset_chooser; |
80 clear_candidates(); |
84 } |
81 } |
85 |
82 |
86 void G1CollectionSet::init_region_lengths(uint eden_cset_region_length, |
83 void G1CollectionSet::init_region_lengths(uint eden_cset_region_length, |
87 uint survivor_cset_region_length) { |
84 uint survivor_cset_region_length) { |
88 assert_at_safepoint_on_vm_thread(); |
85 assert_at_safepoint_on_vm_thread(); |
116 _optional_region_max_length = 0; |
113 _optional_region_max_length = 0; |
117 if (_optional_regions != NULL) { |
114 if (_optional_regions != NULL) { |
118 FREE_C_HEAP_ARRAY(HeapRegion*, _optional_regions); |
115 FREE_C_HEAP_ARRAY(HeapRegion*, _optional_regions); |
119 _optional_regions = NULL; |
116 _optional_regions = NULL; |
120 } |
117 } |
|
118 } |
|
119 |
|
120 void G1CollectionSet::clear_candidates() { |
|
121 delete _candidates; |
|
122 _candidates = NULL; |
121 } |
123 } |
122 |
124 |
123 void G1CollectionSet::set_recorded_rs_lengths(size_t rs_lengths) { |
125 void G1CollectionSet::set_recorded_rs_lengths(size_t rs_lengths) { |
124 _recorded_rs_lengths = rs_lengths; |
126 _recorded_rs_lengths = rs_lengths; |
125 } |
127 } |
437 |
439 |
438 return time_remaining_ms; |
440 return time_remaining_ms; |
439 } |
441 } |
440 |
442 |
441 void G1CollectionSet::add_as_old(HeapRegion* hr) { |
443 void G1CollectionSet::add_as_old(HeapRegion* hr) { |
442 cset_chooser()->pop(); // already have region via peek() |
444 candidates()->pop_front(); // already have region via peek() |
443 _g1h->old_set_remove(hr); |
445 _g1h->old_set_remove(hr); |
444 add_old_region(hr); |
446 add_old_region(hr); |
445 } |
447 } |
446 |
448 |
447 void G1CollectionSet::add_as_optional(HeapRegion* hr) { |
449 void G1CollectionSet::add_as_optional(HeapRegion* hr) { |
448 assert(_optional_regions != NULL, "Must not be called before array is allocated"); |
450 assert(_optional_regions != NULL, "Must not be called before array is allocated"); |
449 cset_chooser()->pop(); // already have region via peek() |
451 candidates()->pop_front(); // already have region via peek() |
450 _g1h->old_set_remove(hr); |
452 _g1h->old_set_remove(hr); |
451 add_optional_region(hr); |
453 add_optional_region(hr); |
452 } |
454 } |
453 |
455 |
454 bool G1CollectionSet::optional_is_full() { |
456 bool G1CollectionSet::optional_is_full() { |
478 double predicted_optional_time_ms = 0.0; |
480 double predicted_optional_time_ms = 0.0; |
479 double optional_threshold_ms = time_remaining_ms * _policy->optional_prediction_fraction(); |
481 double optional_threshold_ms = time_remaining_ms * _policy->optional_prediction_fraction(); |
480 uint expensive_region_num = 0; |
482 uint expensive_region_num = 0; |
481 |
483 |
482 if (collector_state()->in_mixed_phase()) { |
484 if (collector_state()->in_mixed_phase()) { |
483 cset_chooser()->verify(); |
485 candidates()->verify(); |
484 const uint min_old_cset_length = _policy->calc_min_old_cset_length(); |
486 const uint min_old_cset_length = _policy->calc_min_old_cset_length(); |
485 const uint max_old_cset_length = MAX2(min_old_cset_length, _policy->calc_max_old_cset_length()); |
487 const uint max_old_cset_length = MAX2(min_old_cset_length, _policy->calc_max_old_cset_length()); |
486 bool check_time_remaining = _policy->adaptive_young_list_length(); |
488 bool check_time_remaining = _policy->adaptive_young_list_length(); |
487 |
489 |
488 initialize_optional(max_old_cset_length - min_old_cset_length); |
490 initialize_optional(max_old_cset_length - min_old_cset_length); |
489 log_debug(gc, ergo, cset)("Start adding old regions for mixed gc. min %u regions, max %u regions, " |
491 log_debug(gc, ergo, cset)("Start adding old regions for mixed gc. min %u regions, max %u regions, " |
490 "time remaining %1.2fms, optional threshold %1.2fms", |
492 "time remaining %1.2fms, optional threshold %1.2fms", |
491 min_old_cset_length, max_old_cset_length, time_remaining_ms, optional_threshold_ms); |
493 min_old_cset_length, max_old_cset_length, time_remaining_ms, optional_threshold_ms); |
492 |
494 |
493 HeapRegion* hr = cset_chooser()->peek(); |
495 HeapRegion* hr = candidates()->peek_front(); |
494 while (hr != NULL) { |
496 while (hr != NULL) { |
495 if (old_region_length() + optional_region_length() >= max_old_cset_length) { |
497 if (old_region_length() + optional_region_length() >= max_old_cset_length) { |
496 // Added maximum number of old regions to the CSet. |
498 // Added maximum number of old regions to the CSet. |
497 log_debug(gc, ergo, cset)("Finish adding old regions to CSet (old CSet region num reached max). " |
499 log_debug(gc, ergo, cset)("Finish adding old regions to CSet (old CSet region num reached max). " |
498 "old %u regions, optional %u regions", |
500 "old %u regions, optional %u regions", |
500 break; |
502 break; |
501 } |
503 } |
502 |
504 |
503 // Stop adding regions if the remaining reclaimable space is |
505 // Stop adding regions if the remaining reclaimable space is |
504 // not above G1HeapWastePercent. |
506 // not above G1HeapWastePercent. |
505 size_t reclaimable_bytes = cset_chooser()->remaining_reclaimable_bytes(); |
507 size_t reclaimable_bytes = candidates()->remaining_reclaimable_bytes(); |
506 double reclaimable_percent = _policy->reclaimable_bytes_percent(reclaimable_bytes); |
508 double reclaimable_percent = _policy->reclaimable_bytes_percent(reclaimable_bytes); |
507 double threshold = (double) G1HeapWastePercent; |
509 double threshold = (double) G1HeapWastePercent; |
508 if (reclaimable_percent <= threshold) { |
510 if (reclaimable_percent <= threshold) { |
509 // We've added enough old regions that the amount of uncollected |
511 // We've added enough old regions that the amount of uncollected |
510 // reclaimable space is at or below the waste threshold. Stop |
512 // reclaimable space is at or below the waste threshold. Stop |
549 } else { |
551 } else { |
550 log_debug(gc, ergo, cset)("Finish adding old regions to CSet (predicted time is too high)."); |
552 log_debug(gc, ergo, cset)("Finish adding old regions to CSet (predicted time is too high)."); |
551 break; |
553 break; |
552 } |
554 } |
553 } |
555 } |
554 hr = cset_chooser()->peek(); |
556 hr = candidates()->peek_front(); |
555 } |
557 } |
556 if (hr == NULL) { |
558 if (hr == NULL) { |
557 log_debug(gc, ergo, cset)("Finish adding old regions to CSet (candidate old regions not available)"); |
559 log_debug(gc, ergo, cset)("Finish adding old regions to CSet (candidate old regions not available)"); |
558 } |
560 } |
559 |
561 |
560 cset_chooser()->verify(); |
562 candidates()->verify(); |
561 } |
563 } |
562 |
564 |
563 stop_incremental_building(); |
565 stop_incremental_building(); |
564 |
566 |
565 log_debug(gc, ergo, cset)("Finish choosing CSet regions old: %u, optional: %u, " |
567 log_debug(gc, ergo, cset)("Finish choosing CSet regions old: %u, optional: %u, " |
628 } |
630 } |
629 |
631 |
630 G1OptionalCSet::~G1OptionalCSet() { |
632 G1OptionalCSet::~G1OptionalCSet() { |
631 G1CollectedHeap* g1h = G1CollectedHeap::heap(); |
633 G1CollectedHeap* g1h = G1CollectedHeap::heap(); |
632 while (!is_empty()) { |
634 while (!is_empty()) { |
633 // We want to return regions not evacuated to the |
635 // We want to return regions not evacuated to the collection set candidates |
634 // chooser in reverse order to maintain the old order. |
636 // in reverse order to maintain the old order. |
635 HeapRegion* hr = _cset->remove_last_optional_region(); |
637 HeapRegion* hr = _cset->remove_last_optional_region(); |
636 assert(hr != NULL, "Should be valid region left"); |
638 assert(hr != NULL, "Should be valid region left"); |
637 _pset->record_unused_optional_region(hr); |
639 _pset->record_unused_optional_region(hr); |
638 g1h->old_set_add(hr); |
640 g1h->old_set_add(hr); |
639 g1h->clear_in_cset(hr); |
641 g1h->clear_in_cset(hr); |
640 hr->set_index_in_opt_cset(InvalidCSetIndex); |
642 hr->set_index_in_opt_cset(InvalidCSetIndex); |
641 _cset->cset_chooser()->push(hr); |
643 _cset->candidates()->push_front(hr); |
642 } |
644 } |
643 _cset->free_optional_regions(); |
645 _cset->free_optional_regions(); |
644 } |
646 } |
645 |
647 |
646 uint G1OptionalCSet::size() { |
648 uint G1OptionalCSet::size() { |