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