提交 4a18c97a 编写于 作者: T tonyp

7075646: G1: fix inconsistencies in the monitoring data

Summary: Fixed a few inconsistencies in the monitoring data, in particular when reported from jstat.
Reviewed-by: jmasa, brutisso, johnc
上级 9c3adbcc
......@@ -816,6 +816,11 @@ HeapWord* G1CollectedHeap::humongous_obj_allocate(size_t word_size) {
result =
humongous_obj_allocate_initialize_regions(first, num_regions, word_size);
assert(result != NULL, "it should always return a valid result");
// A successful humongous object allocation changes the used space
// information of the old generation so we need to recalculate the
// sizes and update the jstat counters here.
g1mm()->update_sizes();
}
verify_region_sets_optional();
......@@ -1422,7 +1427,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
if (PrintHeapAtGC) {
Universe::print_heap_after_gc();
}
g1mm()->update_counters();
g1mm()->update_sizes();
post_full_gc_dump();
return true;
......@@ -1790,6 +1795,7 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) :
_evac_failure_scan_stack(NULL) ,
_mark_in_progress(false),
_cg1r(NULL), _summary_bytes_used(0),
_g1mm(NULL),
_refine_cte_cl(NULL),
_full_collection(false),
_free_list("Master Free List"),
......@@ -2069,7 +2075,7 @@ jint G1CollectedHeap::initialize() {
// Do create of the monitoring and management support so that
// values in the heap have been properly initialized.
_g1mm = new G1MonitoringSupport(this, &_g1_storage);
_g1mm = new G1MonitoringSupport(this);
return JNI_OK;
}
......@@ -3702,7 +3708,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
if (PrintHeapAtGC) {
Universe::print_heap_after_gc();
}
g1mm()->update_counters();
g1mm()->update_sizes();
if (G1SummarizeRSetStats &&
(G1SummarizeRSetStatsPeriod > 0) &&
......@@ -5815,7 +5821,6 @@ HeapRegion* G1CollectedHeap::new_mutator_alloc_region(size_t word_size,
g1_policy()->update_region_num(true /* next_is_young */);
set_region_short_lived_locked(new_alloc_region);
_hr_printer.alloc(new_alloc_region, G1HRPrinter::Eden, young_list_full);
g1mm()->update_eden_counters();
return new_alloc_region;
}
}
......@@ -5830,6 +5835,10 @@ void G1CollectedHeap::retire_mutator_alloc_region(HeapRegion* alloc_region,
g1_policy()->add_region_to_incremental_cset_lhs(alloc_region);
_summary_bytes_used += allocated_bytes;
_hr_printer.retire(alloc_region);
// We update the eden sizes here, when the region is retired,
// instead of when it's allocated, since this is the point that its
// used space has been recored in _summary_bytes_used.
g1mm()->update_eden_size();
}
HeapRegion* MutatorAllocRegion::allocate_new_region(size_t word_size,
......
......@@ -597,7 +597,10 @@ protected:
public:
G1MonitoringSupport* g1mm() { return _g1mm; }
G1MonitoringSupport* g1mm() {
assert(_g1mm != NULL, "should have been initialized");
return _g1mm;
}
// Expand the garbage-first heap by at least the given size (in bytes!).
// Returns true if the heap was expanded by the requested amount;
......
......@@ -1149,6 +1149,10 @@ public:
return young_list_length < young_list_max_length;
}
size_t young_list_max_length() {
return _young_list_max_length;
}
void update_region_num(bool young);
bool full_young_gcs() {
......
......@@ -27,19 +27,69 @@
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#include "gc_implementation/g1/g1CollectorPolicy.hpp"
G1MonitoringSupport::G1MonitoringSupport(G1CollectedHeap* g1h,
VirtualSpace* g1_storage_addr) :
G1GenerationCounters::G1GenerationCounters(G1MonitoringSupport* g1mm,
const char* name,
int ordinal, int spaces,
size_t min_capacity,
size_t max_capacity,
size_t curr_capacity)
: GenerationCounters(name, ordinal, spaces, min_capacity,
max_capacity, curr_capacity), _g1mm(g1mm) { }
// We pad the capacity three times given that the young generation
// contains three spaces (eden and two survivors).
G1YoungGenerationCounters::G1YoungGenerationCounters(G1MonitoringSupport* g1mm,
const char* name)
: G1GenerationCounters(g1mm, name, 0 /* ordinal */, 3 /* spaces */,
G1MonitoringSupport::pad_capacity(0, 3) /* min_capacity */,
G1MonitoringSupport::pad_capacity(g1mm->young_gen_max(), 3),
G1MonitoringSupport::pad_capacity(0, 3) /* curr_capacity */) {
update_all();
}
G1OldGenerationCounters::G1OldGenerationCounters(G1MonitoringSupport* g1mm,
const char* name)
: G1GenerationCounters(g1mm, name, 1 /* ordinal */, 1 /* spaces */,
G1MonitoringSupport::pad_capacity(0) /* min_capacity */,
G1MonitoringSupport::pad_capacity(g1mm->old_gen_max()),
G1MonitoringSupport::pad_capacity(0) /* curr_capacity */) {
update_all();
}
void G1YoungGenerationCounters::update_all() {
size_t committed =
G1MonitoringSupport::pad_capacity(_g1mm->young_gen_committed(), 3);
_current_size->set_value(committed);
}
void G1OldGenerationCounters::update_all() {
size_t committed =
G1MonitoringSupport::pad_capacity(_g1mm->old_gen_committed());
_current_size->set_value(committed);
}
G1MonitoringSupport::G1MonitoringSupport(G1CollectedHeap* g1h) :
_g1h(g1h),
_incremental_collection_counters(NULL),
_full_collection_counters(NULL),
_non_young_collection_counters(NULL),
_old_collection_counters(NULL),
_old_space_counters(NULL),
_young_collection_counters(NULL),
_eden_counters(NULL),
_from_counters(NULL),
_to_counters(NULL),
_g1_storage_addr(g1_storage_addr)
{
_overall_reserved(0),
_overall_committed(0), _overall_used(0),
_young_region_num(0),
_young_gen_committed(0),
_eden_committed(0), _eden_used(0),
_survivor_committed(0), _survivor_used(0),
_old_committed(0), _old_used(0) {
_overall_reserved = g1h->max_capacity();
recalculate_sizes();
// Counters for GC collections
//
// name "collector.0". In a generational collector this would be the
......@@ -69,110 +119,147 @@ G1MonitoringSupport::G1MonitoringSupport(G1CollectedHeap* g1h,
// generational GC terms. The "1, 1" parameters are for
// the n-th generation (=1) with 1 space.
// Counters are created from minCapacity, maxCapacity, and capacity
_non_young_collection_counters =
new GenerationCounters("whole heap", 1, 1, _g1_storage_addr);
_old_collection_counters = new G1OldGenerationCounters(this, "old");
// name "generation.1.space.0"
// Counters are created from maxCapacity, capacity, initCapacity,
// and used.
_old_space_counters = new HSpaceCounters("space", 0,
_g1h->max_capacity(), _g1h->capacity(), _non_young_collection_counters);
_old_space_counters = new HSpaceCounters("space", 0 /* ordinal */,
pad_capacity(overall_reserved()) /* max_capacity */,
pad_capacity(old_space_committed()) /* init_capacity */,
_old_collection_counters);
// Young collection set
// name "generation.0". This is logically the young generation.
// The "0, 3" are paremeters for the n-th genertaion (=0) with 3 spaces.
// See _non_young_collection_counters for additional counters
_young_collection_counters = new GenerationCounters("young", 0, 3, NULL);
// See _old_collection_counters for additional counters
_young_collection_counters = new G1YoungGenerationCounters(this, "young");
// Replace "max_heap_byte_size() with maximum young gen size for
// g1Collectedheap
// name "generation.0.space.0"
// See _old_space_counters for additional counters
_eden_counters = new HSpaceCounters("eden", 0,
_g1h->max_capacity(), eden_space_committed(),
_eden_counters = new HSpaceCounters("eden", 0 /* ordinal */,
pad_capacity(overall_reserved()) /* max_capacity */,
pad_capacity(eden_space_committed()) /* init_capacity */,
_young_collection_counters);
// name "generation.0.space.1"
// See _old_space_counters for additional counters
// Set the arguments to indicate that this survivor space is not used.
_from_counters = new HSpaceCounters("s0", 1, (long) 0, (long) 0,
_from_counters = new HSpaceCounters("s0", 1 /* ordinal */,
pad_capacity(0) /* max_capacity */,
pad_capacity(0) /* init_capacity */,
_young_collection_counters);
// Given that this survivor space is not used, we update it here
// once to reflect that its used space is 0 so that we don't have to
// worry about updating it again later.
_from_counters->update_used(0);
// name "generation.0.space.2"
// See _old_space_counters for additional counters
_to_counters = new HSpaceCounters("s1", 2,
_g1h->max_capacity(),
survivor_space_committed(),
_to_counters = new HSpaceCounters("s1", 2 /* ordinal */,
pad_capacity(overall_reserved()) /* max_capacity */,
pad_capacity(survivor_space_committed()) /* init_capacity */,
_young_collection_counters);
}
size_t G1MonitoringSupport::overall_committed() {
return g1h()->capacity();
}
void G1MonitoringSupport::recalculate_sizes() {
G1CollectedHeap* g1 = g1h();
size_t G1MonitoringSupport::overall_used() {
return g1h()->used_unlocked();
}
// Recalculate all the sizes from scratch. We assume that this is
// called at a point where no concurrent updates to the various
// values we read here are possible (i.e., at a STW phase at the end
// of a GC).
size_t G1MonitoringSupport::eden_space_committed() {
return MAX2(eden_space_used(), (size_t) HeapRegion::GrainBytes);
}
size_t young_list_length = g1->young_list()->length();
size_t survivor_list_length = g1->g1_policy()->recorded_survivor_regions();
assert(young_list_length >= survivor_list_length, "invariant");
size_t eden_list_length = young_list_length - survivor_list_length;
// Max length includes any potential extensions to the young gen
// we'll do when the GC locker is active.
size_t young_list_max_length = g1->g1_policy()->young_list_max_length();
assert(young_list_max_length >= survivor_list_length, "invariant");
size_t eden_list_max_length = young_list_max_length - survivor_list_length;
size_t G1MonitoringSupport::eden_space_used() {
size_t young_list_length = g1h()->young_list()->length();
size_t eden_used = young_list_length * HeapRegion::GrainBytes;
size_t survivor_used = survivor_space_used();
eden_used = subtract_up_to_zero(eden_used, survivor_used);
return eden_used;
}
_overall_used = g1->used_unlocked();
_eden_used = eden_list_length * HeapRegion::GrainBytes;
_survivor_used = survivor_list_length * HeapRegion::GrainBytes;
_young_region_num = young_list_length;
_old_used = subtract_up_to_zero(_overall_used, _eden_used + _survivor_used);
size_t G1MonitoringSupport::survivor_space_committed() {
return MAX2(survivor_space_used(),
(size_t) HeapRegion::GrainBytes);
}
// First calculate the committed sizes that can be calculated independently.
_survivor_committed = _survivor_used;
_old_committed = HeapRegion::align_up_to_region_byte_size(_old_used);
size_t G1MonitoringSupport::survivor_space_used() {
size_t survivor_num = g1h()->g1_policy()->recorded_survivor_regions();
size_t survivor_used = survivor_num * HeapRegion::GrainBytes;
return survivor_used;
}
// Next, start with the overall committed size.
_overall_committed = g1->capacity();
size_t committed = _overall_committed;
size_t G1MonitoringSupport::old_space_committed() {
size_t committed = overall_committed();
size_t eden_committed = eden_space_committed();
size_t survivor_committed = survivor_space_committed();
committed = subtract_up_to_zero(committed, eden_committed);
committed = subtract_up_to_zero(committed, survivor_committed);
committed = MAX2(committed, (size_t) HeapRegion::GrainBytes);
return committed;
// Remove the committed size we have calculated so far (for the
// survivor and old space).
assert(committed >= (_survivor_committed + _old_committed), "sanity");
committed -= _survivor_committed + _old_committed;
// Next, calculate and remove the committed size for the eden.
_eden_committed = eden_list_max_length * HeapRegion::GrainBytes;
// Somewhat defensive: be robust in case there are inaccuracies in
// the calculations
_eden_committed = MIN2(_eden_committed, committed);
committed -= _eden_committed;
// Finally, give the rest to the old space...
_old_committed += committed;
// ..and calculate the young gen committed.
_young_gen_committed = _eden_committed + _survivor_committed;
assert(_overall_committed ==
(_eden_committed + _survivor_committed + _old_committed),
"the committed sizes should add up");
// Somewhat defensive: cap the eden used size to make sure it
// never exceeds the committed size.
_eden_used = MIN2(_eden_used, _eden_committed);
// _survivor_committed and _old_committed are calculated in terms of
// the corresponding _*_used value, so the next two conditions
// should hold.
assert(_survivor_used <= _survivor_committed, "post-condition");
assert(_old_used <= _old_committed, "post-condition");
}
// See the comment near the top of g1MonitoringSupport.hpp for
// an explanation of these calculations for "used" and "capacity".
size_t G1MonitoringSupport::old_space_used() {
size_t used = overall_used();
size_t eden_used = eden_space_used();
size_t survivor_used = survivor_space_used();
used = subtract_up_to_zero(used, eden_used);
used = subtract_up_to_zero(used, survivor_used);
return used;
void G1MonitoringSupport::recalculate_eden_size() {
G1CollectedHeap* g1 = g1h();
// When a new eden region is allocated, only the eden_used size is
// affected (since we have recalculated everything else at the last GC).
size_t young_region_num = g1h()->young_list()->length();
if (young_region_num > _young_region_num) {
size_t diff = young_region_num - _young_region_num;
_eden_used += diff * HeapRegion::GrainBytes;
// Somewhat defensive: cap the eden used size to make sure it
// never exceeds the committed size.
_eden_used = MIN2(_eden_used, _eden_committed);
_young_region_num = young_region_num;
}
}
void G1MonitoringSupport::update_counters() {
void G1MonitoringSupport::update_sizes() {
recalculate_sizes();
if (UsePerfData) {
eden_counters()->update_capacity(eden_space_committed());
eden_counters()->update_capacity(pad_capacity(eden_space_committed()));
eden_counters()->update_used(eden_space_used());
to_counters()->update_capacity(survivor_space_committed());
// only the to survivor space (s1) is active, so we don't need to
// update the counteres for the from survivor space (s0)
to_counters()->update_capacity(pad_capacity(survivor_space_committed()));
to_counters()->update_used(survivor_space_used());
old_space_counters()->update_capacity(old_space_committed());
old_space_counters()->update_capacity(pad_capacity(old_space_committed()));
old_space_counters()->update_used(old_space_used());
non_young_collection_counters()->update_all();
old_collection_counters()->update_all();
young_collection_counters()->update_all();
}
}
void G1MonitoringSupport::update_eden_counters() {
void G1MonitoringSupport::update_eden_size() {
recalculate_eden_size();
if (UsePerfData) {
eden_counters()->update_capacity(eden_space_committed());
eden_counters()->update_used(eden_space_used());
}
}
......@@ -28,101 +28,93 @@
#include "gc_implementation/shared/hSpaceCounters.hpp"
class G1CollectedHeap;
class G1SpaceMonitoringSupport;
// Class for monitoring logical spaces in G1.
// G1 defines a set of regions as a young
// collection (analogous to a young generation).
// The young collection is a logical generation
// with no fixed chunk (see space.hpp) reflecting
// the address space for the generation. In addition
// to the young collection there is its complement
// the non-young collection that is simply the regions
// not in the young collection. The non-young collection
// is treated here as a logical old generation only
// because the monitoring tools expect a generational
// heap. The monitoring tools expect that a Space
// (see space.hpp) exists that describe the
// address space of young collection and non-young
// collection and such a view is provided here.
//
// This class provides interfaces to access
// the value of variables for the young collection
// that include the "capacity" and "used" of the
// young collection along with constant values
// for the minimum and maximum capacities for
// the logical spaces. Similarly for the non-young
// collection.
//
// Also provided are counters for G1 concurrent collections
// and stop-the-world full heap collecitons.
//
// Below is a description of how "used" and "capactiy"
// (or committed) is calculated for the logical spaces.
//
// 1) The used space calculation for a pool is not necessarily
// independent of the others. We can easily get from G1 the overall
// used space in the entire heap, the number of regions in the young
// generation (includes both eden and survivors), and the number of
// survivor regions. So, from that we calculate:
//
// survivor_used = survivor_num * region_size
// eden_used = young_region_num * region_size - survivor_used
// old_gen_used = overall_used - eden_used - survivor_used
//
// Note that survivor_used and eden_used are upper bounds. To get the
// actual value we would have to iterate over the regions and add up
// ->used(). But that'd be expensive. So, we'll accept some lack of
// accuracy for those two. But, we have to be careful when calculating
// old_gen_used, in case we subtract from overall_used more then the
// actual number and our result goes negative.
//
// 2) Calculating the used space is straightforward, as described
// above. However, how do we calculate the committed space, given that
// we allocate space for the eden, survivor, and old gen out of the
// same pool of regions? One way to do this is to use the used value
// as also the committed value for the eden and survivor spaces and
// then calculate the old gen committed space as follows:
//
// old_gen_committed = overall_committed - eden_committed - survivor_committed
//
// Maybe a better way to do that would be to calculate used for eden
// and survivor as a sum of ->used() over their regions and then
// calculate committed as region_num * region_size (i.e., what we use
// to calculate the used space now). This is something to consider
// in the future.
//
// 3) Another decision that is again not straightforward is what is
// the max size that each memory pool can grow to. One way to do this
// would be to use the committed size for the max for the eden and
// survivors and calculate the old gen max as follows (basically, it's
// a similar pattern to what we use for the committed space, as
// described above):
//
// old_gen_max = overall_max - eden_max - survivor_max
//
// Unfortunately, the above makes the max of each pool fluctuate over
// time and, even though this is allowed according to the spec, it
// broke several assumptions in the M&M framework (there were cases
// where used would reach a value greater than max). So, for max we
// use -1, which means "undefined" according to the spec.
//
// 4) Now, there is a very subtle issue with all the above. The
// framework will call get_memory_usage() on the three pools
// asynchronously. As a result, each call might get a different value
// for, say, survivor_num which will yield inconsistent values for
// eden_used, survivor_used, and old_gen_used (as survivor_num is used
// in the calculation of all three). This would normally be
// ok. However, it's possible that this might cause the sum of
// eden_used, survivor_used, and old_gen_used to go over the max heap
// size and this seems to sometimes cause JConsole (and maybe other
// clients) to get confused. There's not a really an easy / clean
// solution to this problem, due to the asynchrounous nature of the
// framework.
// Class for monitoring logical spaces in G1. It provides data for
// both G1's jstat counters as well as G1's memory pools.
//
// G1 splits the heap into heap regions and each heap region belongs
// to one of the following categories:
//
// * eden : regions that have been allocated since the last GC
// * survivors : regions with objects that survived the last few GCs
// * old : long-lived non-humongous regions
// * humongous : humongous regions
// * free : free regions
//
// The combination of eden and survivor regions form the equivalent of
// the young generation in the other GCs. The combination of old and
// humongous regions form the equivalent of the old generation in the
// other GCs. Free regions do not have a good equivalent in the other
// GCs given that they can be allocated as any of the other region types.
//
// The monitoring tools expect the heap to contain a number of
// generations (young, old, perm) and each generation to contain a
// number of spaces (young: eden, survivors, old). Given that G1 does
// not maintain those spaces physically (e.g., the set of
// non-contiguous eden regions can be considered as a "logical"
// space), we'll provide the illusion that those generations and
// spaces exist. In reality, each generation and space refers to a set
// of heap regions that are potentially non-contiguous.
//
// This class provides interfaces to access the min, current, and max
// capacity and current occupancy for each of G1's logical spaces and
// generations we expose to the monitoring tools. Also provided are
// counters for G1 concurrent collections and stop-the-world full heap
// collections.
//
// Below is a description of how the various sizes are calculated.
//
// * Current Capacity
//
// - heap_capacity = current heap capacity (e.g., current committed size)
// - young_gen_capacity = current max young gen target capacity
// (i.e., young gen target capacity + max allowed expansion capacity)
// - survivor_capacity = current survivor region capacity
// - eden_capacity = young_gen_capacity - survivor_capacity
// - old_capacity = heap_capacity - young_gen_capacity
//
// What we do in the above is to distribute the free regions among
// eden_capacity and old_capacity.
//
// * Occupancy
//
// - young_gen_used = current young region capacity
// - survivor_used = survivor_capacity
// - eden_used = young_gen_used - survivor_used
// - old_used = overall_used - young_gen_used
//
// Unfortunately, we currently only keep track of the number of
// currently allocated young and survivor regions + the overall used
// bytes in the heap, so the above can be a little inaccurate.
//
// * Min Capacity
//
// We set this to 0 for all spaces. We could consider setting the old
// min capacity to the min capacity of the heap (see 7078465).
//
// * Max Capacity
//
// For jstat, we set the max capacity of all spaces to heap_capacity,
// given that we don't always have a reasonably upper bound on how big
// each space can grow. For the memory pools, we actually make the max
// capacity undefined. We could consider setting the old max capacity
// to the max capacity of the heap (see 7078465).
//
// If we had more accurate occupancy / capacity information per
// region set the above calculations would be greatly simplified and
// be made more accurate.
//
// We update all the above synchronously and we store the results in
// fields so that we just read said fields when needed. A subtle point
// is that all the above sizes need to be recalculated when the old
// gen changes capacity (after a GC or after a humongous allocation)
// but only the eden occupancy changes when a new eden region is
// allocated. So, in the latter case we have minimal recalcuation to
// do which is important as we want to keep the eden region allocation
// path as low-overhead as possible.
class G1MonitoringSupport : public CHeapObj {
G1CollectedHeap* _g1h;
VirtualSpace* _g1_storage_addr;
// jstat performance counters
// incremental collections both fully and partially young
......@@ -133,9 +125,9 @@ class G1MonitoringSupport : public CHeapObj {
// _from_counters, and _to_counters are associated with
// this "generational" counter.
GenerationCounters* _young_collection_counters;
// non-young collection set counters. The _old_space_counters
// old collection set counters. The _old_space_counters
// below are associated with this "generational" counter.
GenerationCounters* _non_young_collection_counters;
GenerationCounters* _old_collection_counters;
// Counters for the capacity and used for
// the whole heap
HSpaceCounters* _old_space_counters;
......@@ -145,6 +137,27 @@ class G1MonitoringSupport : public CHeapObj {
HSpaceCounters* _from_counters;
HSpaceCounters* _to_counters;
// When it's appropriate to recalculate the various sizes (at the
// end of a GC, when a new eden region is allocated, etc.) we store
// them here so that we can easily report them when needed and not
// have to recalculate them every time.
size_t _overall_reserved;
size_t _overall_committed;
size_t _overall_used;
size_t _young_region_num;
size_t _young_gen_committed;
size_t _eden_committed;
size_t _eden_used;
size_t _survivor_committed;
size_t _survivor_used;
size_t _old_committed;
size_t _old_used;
G1CollectedHeap* g1h() { return _g1h; }
// It returns x - y if x > y, 0 otherwise.
// As described in the comment above, some of the inputs to the
// calculations we have to do are obtained concurrently and hence
......@@ -160,15 +173,35 @@ class G1MonitoringSupport : public CHeapObj {
}
}
// Recalculate all the sizes.
void recalculate_sizes();
// Recalculate only what's necessary when a new eden region is allocated.
void recalculate_eden_size();
public:
G1MonitoringSupport(G1CollectedHeap* g1h, VirtualSpace* g1_storage_addr);
G1MonitoringSupport(G1CollectedHeap* g1h);
G1CollectedHeap* g1h() { return _g1h; }
VirtualSpace* g1_storage_addr() { return _g1_storage_addr; }
// Unfortunately, the jstat tool assumes that no space has 0
// capacity. In our case, given that each space is logical, it's
// possible that no regions will be allocated to it, hence to have 0
// capacity (e.g., if there are no survivor regions, the survivor
// space has 0 capacity). The way we deal with this is to always pad
// each capacity value we report to jstat by a very small amount to
// make sure that it's never zero. Given that we sometimes have to
// report a capacity of a generation that contains several spaces
// (e.g., young gen includes one eden, two survivor spaces), the
// mult parameter is provided in order to adding the appropriate
// padding multiple times so that the capacities add up correctly.
static size_t pad_capacity(size_t size_bytes, size_t mult = 1) {
return size_bytes + MinObjAlignmentInBytes * mult;
}
// Performance Counter accessors
void update_counters();
void update_eden_counters();
// Recalculate all the sizes from scratch and update all the jstat
// counters accordingly.
void update_sizes();
// Recalculate only what's necessary when a new eden region is
// allocated and update any jstat counters that need to be updated.
void update_eden_size();
CollectorCounters* incremental_collection_counters() {
return _incremental_collection_counters;
......@@ -176,8 +209,11 @@ class G1MonitoringSupport : public CHeapObj {
CollectorCounters* full_collection_counters() {
return _full_collection_counters;
}
GenerationCounters* non_young_collection_counters() {
return _non_young_collection_counters;
GenerationCounters* young_collection_counters() {
return _young_collection_counters;
}
GenerationCounters* old_collection_counters() {
return _old_collection_counters;
}
HSpaceCounters* old_space_counters() { return _old_space_counters; }
HSpaceCounters* eden_counters() { return _eden_counters; }
......@@ -187,17 +223,45 @@ class G1MonitoringSupport : public CHeapObj {
// Monitoring support used by
// MemoryService
// jstat counters
size_t overall_committed();
size_t overall_used();
size_t eden_space_committed();
size_t eden_space_used();
size_t overall_reserved() { return _overall_reserved; }
size_t overall_committed() { return _overall_committed; }
size_t overall_used() { return _overall_used; }
size_t young_gen_committed() { return _young_gen_committed; }
size_t young_gen_max() { return overall_reserved(); }
size_t eden_space_committed() { return _eden_committed; }
size_t eden_space_used() { return _eden_used; }
size_t survivor_space_committed() { return _survivor_committed; }
size_t survivor_space_used() { return _survivor_used; }
size_t old_gen_committed() { return old_space_committed(); }
size_t old_gen_max() { return overall_reserved(); }
size_t old_space_committed() { return _old_committed; }
size_t old_space_used() { return _old_used; }
};
size_t survivor_space_committed();
size_t survivor_space_used();
class G1GenerationCounters: public GenerationCounters {
protected:
G1MonitoringSupport* _g1mm;
public:
G1GenerationCounters(G1MonitoringSupport* g1mm,
const char* name, int ordinal, int spaces,
size_t min_capacity, size_t max_capacity,
size_t curr_capacity);
};
class G1YoungGenerationCounters: public G1GenerationCounters {
public:
G1YoungGenerationCounters(G1MonitoringSupport* g1mm, const char* name);
virtual void update_all();
};
size_t old_space_committed();
size_t old_space_used();
class G1OldGenerationCounters: public G1GenerationCounters {
public:
G1OldGenerationCounters(G1MonitoringSupport* g1mm, const char* name);
virtual void update_all();
};
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1MONITORINGSUPPORT_HPP
......@@ -357,6 +357,11 @@ class HeapRegion: public G1OffsetTableContigSpace {
static int GrainWords;
static int CardsPerRegion;
static size_t align_up_to_region_byte_size(size_t sz) {
return (sz + (size_t) GrainBytes - 1) &
~((1 << (size_t) LogOfHRGrainBytes) - 1);
}
// It sets up the heap region size (GrainBytes / GrainWords), as
// well as other related fields that are based on the heap region
// size (LogOfHRGrainBytes / LogOfHRGrainWords /
......
......@@ -26,14 +26,10 @@
#include "gc_implementation/shared/generationCounters.hpp"
#include "memory/resourceArea.hpp"
GenerationCounters::GenerationCounters(const char* name,
int ordinal, int spaces,
VirtualSpace* v):
_virtual_space(v) {
void GenerationCounters::initialize(const char* name, int ordinal, int spaces,
size_t min_capacity, size_t max_capacity,
size_t curr_capacity) {
if (UsePerfData) {
EXCEPTION_MARK;
ResourceMark rm;
......@@ -51,18 +47,37 @@ GenerationCounters::GenerationCounters(const char* name,
cname = PerfDataManager::counter_name(_name_space, "minCapacity");
PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_Bytes,
_virtual_space == NULL ? 0 :
_virtual_space->committed_size(), CHECK);
min_capacity, CHECK);
cname = PerfDataManager::counter_name(_name_space, "maxCapacity");
PerfDataManager::create_constant(SUN_GC, cname, PerfData::U_Bytes,
_virtual_space == NULL ? 0 :
_virtual_space->reserved_size(), CHECK);
max_capacity, CHECK);
cname = PerfDataManager::counter_name(_name_space, "capacity");
_current_size = PerfDataManager::create_variable(SUN_GC, cname,
PerfData::U_Bytes,
_virtual_space == NULL ? 0 :
_virtual_space->committed_size(), CHECK);
_current_size =
PerfDataManager::create_variable(SUN_GC, cname, PerfData::U_Bytes,
curr_capacity, CHECK);
}
}
GenerationCounters::GenerationCounters(const char* name,
int ordinal, int spaces,
VirtualSpace* v)
: _virtual_space(v) {
assert(v != NULL, "don't call this constructor if v == NULL");
initialize(name, ordinal, spaces,
v->committed_size(), v->reserved_size(), v->committed_size());
}
GenerationCounters::GenerationCounters(const char* name,
int ordinal, int spaces,
size_t min_capacity, size_t max_capacity,
size_t curr_capacity)
: _virtual_space(NULL) {
initialize(name, ordinal, spaces, min_capacity, max_capacity, curr_capacity);
}
void GenerationCounters::update_all() {
assert(_virtual_space != NULL, "otherwise, override this method");
_current_size->set_value(_virtual_space->committed_size());
}
......@@ -34,6 +34,11 @@
class GenerationCounters: public CHeapObj {
friend class VMStructs;
private:
void initialize(const char* name, int ordinal, int spaces,
size_t min_capacity, size_t max_capacity,
size_t curr_capacity);
protected:
PerfVariable* _current_size;
VirtualSpace* _virtual_space;
......@@ -48,11 +53,18 @@ class GenerationCounters: public CHeapObj {
char* _name_space;
// This constructor is only meant for use with the PSGenerationCounters
// constructor. The need for such an constructor should be eliminated
// constructor. The need for such an constructor should be eliminated
// when VirtualSpace and PSVirtualSpace are unified.
GenerationCounters() : _name_space(NULL), _current_size(NULL), _virtual_space(NULL) {}
public:
GenerationCounters()
: _name_space(NULL), _current_size(NULL), _virtual_space(NULL) {}
// This constructor is used for subclasses that do not have a space
// associated with them (e.g, in G1).
GenerationCounters(const char* name, int ordinal, int spaces,
size_t min_capacity, size_t max_capacity,
size_t curr_capacity);
public:
GenerationCounters(const char* name, int ordinal, int spaces,
VirtualSpace* v);
......@@ -60,10 +72,7 @@ class GenerationCounters: public CHeapObj {
if (_name_space != NULL) FREE_C_HEAP_ARRAY(char, _name_space);
}
virtual void update_all() {
_current_size->set_value(_virtual_space == NULL ? 0 :
_virtual_space->committed_size());
}
virtual void update_all();
const char* name_space() const { return _name_space; }
......
......@@ -32,56 +32,28 @@
G1MemoryPoolSuper::G1MemoryPoolSuper(G1CollectedHeap* g1h,
const char* name,
size_t init_size,
size_t max_size,
bool support_usage_threshold) :
_g1h(g1h), CollectedMemoryPool(name,
MemoryPool::Heap,
init_size,
undefined_max(),
support_usage_threshold) {
_g1mm(g1h->g1mm()), CollectedMemoryPool(name,
MemoryPool::Heap,
init_size,
max_size,
support_usage_threshold) {
assert(UseG1GC, "sanity");
}
// See the comment at the top of g1MemoryPool.hpp
size_t G1MemoryPoolSuper::eden_space_committed(G1CollectedHeap* g1h) {
return MAX2(eden_space_used(g1h), (size_t) HeapRegion::GrainBytes);
}
// See the comment at the top of g1MemoryPool.hpp
size_t G1MemoryPoolSuper::eden_space_used(G1CollectedHeap* g1h) {
return g1h->g1mm()->eden_space_used();
}
// See the comment at the top of g1MemoryPool.hpp
size_t G1MemoryPoolSuper::survivor_space_committed(G1CollectedHeap* g1h) {
return g1h->g1mm()->survivor_space_committed();
}
// See the comment at the top of g1MemoryPool.hpp
size_t G1MemoryPoolSuper::survivor_space_used(G1CollectedHeap* g1h) {
return g1h->g1mm()->survivor_space_used();
}
// See the comment at the top of g1MemoryPool.hpp
size_t G1MemoryPoolSuper::old_space_committed(G1CollectedHeap* g1h) {
return g1h->g1mm()->old_space_committed();
}
// See the comment at the top of g1MemoryPool.hpp
size_t G1MemoryPoolSuper::old_space_used(G1CollectedHeap* g1h) {
return g1h->g1mm()->old_space_used();
}
G1EdenPool::G1EdenPool(G1CollectedHeap* g1h) :
G1MemoryPoolSuper(g1h,
"G1 Eden Space",
eden_space_committed(g1h), /* init_size */
g1h->g1mm()->eden_space_committed(), /* init_size */
_undefined_max,
false /* support_usage_threshold */) { }
MemoryUsage G1EdenPool::get_memory_usage() {
size_t initial_sz = initial_size();
size_t max_sz = max_size();
size_t used = used_in_bytes();
size_t committed = eden_space_committed(_g1h);
size_t committed = _g1mm->eden_space_committed();
return MemoryUsage(initial_sz, used, committed, max_sz);
}
......@@ -89,14 +61,15 @@ MemoryUsage G1EdenPool::get_memory_usage() {
G1SurvivorPool::G1SurvivorPool(G1CollectedHeap* g1h) :
G1MemoryPoolSuper(g1h,
"G1 Survivor Space",
survivor_space_committed(g1h), /* init_size */
g1h->g1mm()->survivor_space_committed(), /* init_size */
_undefined_max,
false /* support_usage_threshold */) { }
MemoryUsage G1SurvivorPool::get_memory_usage() {
size_t initial_sz = initial_size();
size_t max_sz = max_size();
size_t used = used_in_bytes();
size_t committed = survivor_space_committed(_g1h);
size_t committed = _g1mm->survivor_space_committed();
return MemoryUsage(initial_sz, used, committed, max_sz);
}
......@@ -104,14 +77,15 @@ MemoryUsage G1SurvivorPool::get_memory_usage() {
G1OldGenPool::G1OldGenPool(G1CollectedHeap* g1h) :
G1MemoryPoolSuper(g1h,
"G1 Old Gen",
old_space_committed(g1h), /* init_size */
g1h->g1mm()->old_space_committed(), /* init_size */
_undefined_max,
true /* support_usage_threshold */) { }
MemoryUsage G1OldGenPool::get_memory_usage() {
size_t initial_sz = initial_size();
size_t max_sz = max_size();
size_t used = used_in_bytes();
size_t committed = old_space_committed(_g1h);
size_t committed = _g1mm->old_space_committed();
return MemoryUsage(initial_sz, used, committed, max_sz);
}
......@@ -26,12 +26,11 @@
#define SHARE_VM_SERVICES_G1MEMORYPOOL_HPP
#ifndef SERIALGC
#include "gc_implementation/g1/g1MonitoringSupport.hpp"
#include "services/memoryPool.hpp"
#include "services/memoryUsage.hpp"
#endif
class G1CollectedHeap;
// This file contains the three classes that represent the memory
// pools of the G1 spaces: G1EdenPool, G1SurvivorPool, and
// G1OldGenPool. In G1, unlike our other GCs, we do not have a
......@@ -50,37 +49,19 @@ class G1CollectedHeap;
// on this model.
//
// This class is shared by the three G1 memory pool classes
// (G1EdenPool, G1SurvivorPool, G1OldGenPool). Given that the way we
// calculate used / committed bytes for these three pools is related
// (see comment above), we put the calculations in this class so that
// we can easily share them among the subclasses.
// (G1EdenPool, G1SurvivorPool, G1OldGenPool).
class G1MemoryPoolSuper : public CollectedMemoryPool {
protected:
G1CollectedHeap* _g1h;
const static size_t _undefined_max = (size_t) -1;
G1MonitoringSupport* _g1mm;
// Would only be called from subclasses.
G1MemoryPoolSuper(G1CollectedHeap* g1h,
const char* name,
size_t init_size,
size_t max_size,
bool support_usage_threshold);
// The reason why all the code is in static methods is so that it
// can be safely called from the constructors of the subclasses.
static size_t undefined_max() {
return (size_t) -1;
}
static size_t eden_space_committed(G1CollectedHeap* g1h);
static size_t eden_space_used(G1CollectedHeap* g1h);
static size_t survivor_space_committed(G1CollectedHeap* g1h);
static size_t survivor_space_used(G1CollectedHeap* g1h);
static size_t old_space_committed(G1CollectedHeap* g1h);
static size_t old_space_used(G1CollectedHeap* g1h);
};
// Memory pool that represents the G1 eden.
......@@ -89,10 +70,10 @@ public:
G1EdenPool(G1CollectedHeap* g1h);
size_t used_in_bytes() {
return eden_space_used(_g1h);
return _g1mm->eden_space_used();
}
size_t max_size() const {
return undefined_max();
return _undefined_max;
}
MemoryUsage get_memory_usage();
};
......@@ -103,10 +84,10 @@ public:
G1SurvivorPool(G1CollectedHeap* g1h);
size_t used_in_bytes() {
return survivor_space_used(_g1h);
return _g1mm->survivor_space_used();
}
size_t max_size() const {
return undefined_max();
return _undefined_max;
}
MemoryUsage get_memory_usage();
};
......@@ -117,10 +98,10 @@ public:
G1OldGenPool(G1CollectedHeap* g1h);
size_t used_in_bytes() {
return old_space_used(_g1h);
return _g1mm->old_space_used();
}
size_t max_size() const {
return undefined_max();
return _undefined_max;
}
MemoryUsage get_memory_usage();
};
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册