blob: 73421d40ee945165a059ca1e6409abeae4cd4a30 [file] [edit]
/*
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_GC_G1_G1COLLECTIONSETCANDIDATES_HPP
#define SHARE_GC_G1_G1COLLECTIONSETCANDIDATES_HPP
#include "gc/g1/g1CardSetMemory.hpp"
#include "gc/g1/g1CollectionSetCandidates.hpp"
#include "gc/shared/gc_globals.hpp"
#include "memory/allocation.hpp"
#include "runtime/globals.hpp"
#include "utilities/growableArray.hpp"
class G1CollectionSetCandidates;
class G1CSetCandidateGroupList;
class G1HeapRegion;
class G1HeapRegionClosure;
struct G1CollectionSetCandidateInfo {
G1HeapRegion* _r;
uint _num_unreclaimed; // Number of GCs this region has been found unreclaimable.
G1CollectionSetCandidateInfo() : G1CollectionSetCandidateInfo(nullptr) { }
G1CollectionSetCandidateInfo(G1HeapRegion* r) : _r(r), _num_unreclaimed(0) { }
bool update_num_unreclaimed() {
++_num_unreclaimed;
return _num_unreclaimed < G1NumCollectionsKeepPinned;
}
static int compare_region_gc_efficiency(G1CollectionSetCandidateInfo* ci1, G1CollectionSetCandidateInfo* ci2);
};
using G1CSetCandidateGroupIterator = GrowableArrayIterator<G1CollectionSetCandidateInfo>;
// G1CSetCandidateGroup groups candidate regions that will be selected for evacuation at the same time.
// Grouping occurs both for candidates from marking or regions retained during evacuation failure, but a group
// can not contain regions from both types of regions.
//
// Humongous objects are excluded from the candidate groups because regions associated with these
// objects are never selected for evacuation.
//
// All regions in the group share a G1CardSet instance, which tracks remembered set entries for the
// regions in the group. We do not have track to cross-region references for regions that are in the
// same group saving memory.
class G1CSetCandidateGroup : public CHeapObj<mtGCCardSet>{
GrowableArray<G1CollectionSetCandidateInfo> _candidates;
G1CardSetMemoryManager _card_set_mm;
// The set of cards in the Java heap
G1CardSet _card_set;
size_t _reclaimable_bytes;
double _gc_efficiency;
// The _group_id is primarily used when printing out per-region liveness information,
// making it easier to associate regions with their assigned G1CSetCandidateGroup, if any.
// Note:
// * _group_id 0 is reserved for special G1CSetCandidateGroups that hold only a single region,
// such as G1CSetCandidateGroups for retained regions.
// * _group_id 1 is reserved for the G1CSetCandidateGroup that contains all young regions.
const uint _group_id;
static uint _next_group_id;
public:
G1CSetCandidateGroup();
G1CSetCandidateGroup(G1CardSetConfiguration* config, G1MonotonicArenaFreePool* card_set_freelist_pool, uint group_id);
~G1CSetCandidateGroup() {
assert(length() == 0, "post condition!");
}
void add(G1HeapRegion* hr);
void add(G1CollectionSetCandidateInfo& hr_info);
uint length() const { return (uint)_candidates.length(); }
G1CardSet* card_set() { return &_card_set; }
const G1CardSet* card_set() const { return &_card_set; }
uint group_id() const { return _group_id; }
void calculate_efficiency();
size_t liveness() const;
// Comparison function to order regions in decreasing GC efficiency order. This
// will cause regions with a lot of live objects and large remembered sets to end
// up at the end of the list.
static int compare_gc_efficiency(G1CSetCandidateGroup** gr1, G1CSetCandidateGroup** gr2);
double gc_efficiency() const { return _gc_efficiency; }
G1HeapRegion* region_at(uint i) const { return _candidates.at(i)._r; }
G1CollectionSetCandidateInfo* at(uint i) { return &_candidates.at(i); }
double predict_group_total_time_ms() const;
G1MonotonicArenaMemoryStats card_set_memory_stats() const {
return _card_set_mm.memory_stats();
}
void clear(bool uninstall_group_cardset = false);
G1CSetCandidateGroupIterator begin() const {
return _candidates.begin();
}
G1CSetCandidateGroupIterator end() const {
return _candidates.end();
}
static void reset_next_group_id() {
_next_group_id = 2;
}
};
using G1CSetCandidateGroupListIterator = GrowableArrayIterator<G1CSetCandidateGroup*>;
class G1CSetCandidateGroupList {
GrowableArray<G1CSetCandidateGroup*> _groups;
volatile uint _num_regions;
public:
G1CSetCandidateGroupList();
void append(G1CSetCandidateGroup* group);
// Delete all groups from the list. The cardset cleanup for regions within the
// groups could have been done elsewhere (e.g. when adding groups to the
// collection set or to retained regions). The uninstall_group_cardset is set to
// true if cleanup needs to happen as we clear the groups from the list.
void clear(bool uninstall_group_cardset = false);
G1CSetCandidateGroup* at(uint index);
uint length() const { return (uint)_groups.length(); }
uint num_regions() const { return _num_regions; }
void remove_selected(uint count, uint num_regions);
// Removes any candidate groups stored in this list and also in the other list. The other
// list may only contain candidate groups in this list, sorted by gc efficiency. It need
// not be a prefix of this list.
// E.g. if this list is "A B G H", the other list may be "A G H", but not "F" (not in
// this list) or "A H G" (wrong order).
void remove(G1CSetCandidateGroupList* other);
void prepare_for_scan();
void sort_by_efficiency();
GrowableArray<G1CSetCandidateGroup*>* groups() {
return &_groups;
}
void verify() const PRODUCT_RETURN;
G1CSetCandidateGroupListIterator begin() const {
return _groups.begin();
}
G1CSetCandidateGroupListIterator end() const {
return _groups.end();
}
template<typename Func>
void iterate(Func&& f) const;
};
// Tracks all collection set candidates, i.e. region groups that could/should be evacuated soon.
//
// These candidate groups are tracked in two list of region groups, sorted by decreasing
// "gc efficiency".
//
// * from_marking_groups: the set of region groups selected by concurrent marking to be
// evacuated to keep overall heap occupancy stable.
// They are guaranteed to be evacuated and cleared out during
// the mixed phase.
//
// * retained_groups: set of region groups selected for evacuation during evacuation
// failure.
// Any young collection will try to evacuate them.
//
class G1CollectionSetCandidates : public CHeapObj<mtGC> {
enum class CandidateOrigin : uint8_t {
Invalid,
Marking, // This region has been determined as candidate by concurrent marking.
Retained, // This region has been added because it has been retained after evacuation.
Verify // Special value for verification.
};
CandidateOrigin* _contains_map;
G1CSetCandidateGroupList _from_marking_groups; // Set of regions selected by concurrent marking.
// Set of regions retained due to evacuation failure. Groups added to this list
// should contain only one region each, making it easier to evacuate retained regions
// in any young collection.
G1CSetCandidateGroupList _retained_groups;
uint _max_regions;
// The number of regions from the last merge of candidates from the marking.
uint _last_marking_candidates_length;
bool is_from_marking(G1HeapRegion* r) const;
public:
G1CollectionSetCandidates();
~G1CollectionSetCandidates();
G1CSetCandidateGroupList& from_marking_groups() { return _from_marking_groups; }
G1CSetCandidateGroupList& retained_groups() { return _retained_groups; }
void initialize(uint max_regions);
void clear();
// Merge collection set candidates from marking into the current marking list
// (which needs to be empty).
void set_candidates_from_marking(G1CollectionSetCandidateInfo* candidate_infos,
uint num_infos);
// The most recent length of the list that had been merged last via
// set_candidates_from_marking(). Used for calculating minimum collection set
// regions.
uint last_marking_candidates_length() const { return _last_marking_candidates_length; }
void sort_by_efficiency();
void sort_marking_by_efficiency();
// Add the given region to the set of retained regions without regards to the
// gc efficiency sorting. The retained regions must be re-sorted manually later.
void add_retained_region_unsorted(G1HeapRegion* r);
// Remove the given groups from the candidates. All given regions must be part
// of the candidates.
void remove(G1CSetCandidateGroupList* other);
bool contains(const G1HeapRegion* r) const;
const char* get_short_type_str(const G1HeapRegion* r) const;
bool is_empty() const;
bool has_more_marking_candidates() const;
uint marking_regions_length() const;
uint retained_regions_length() const;
private:
void verify_helper(G1CSetCandidateGroupList* list, uint& from_marking, CandidateOrigin* verify_map) PRODUCT_RETURN;
public:
void verify() PRODUCT_RETURN;
uint length() const { return marking_regions_length() + retained_regions_length(); }
template<typename Func>
void iterate_regions(Func&& f) const;
};
#endif /* SHARE_GC_G1_G1COLLECTIONSETCANDIDATES_HPP */