--- a/hotspot/src/os/aix/vm/os_aix.cpp Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/src/os/aix/vm/os_aix.cpp Mon Sep 15 15:28:43 2014 +0200
@@ -4002,10 +4002,6 @@
return true;
}
-// int local_vsnprintf(char* buf, size_t count, const char* format, va_list args) {
-// return ::vsnprintf(buf, count, format, args);
-// }
-
// Is a (classpath) directory empty?
bool os::dir_is_empty(const char* path) {
DIR *dir = NULL;
--- a/hotspot/src/os/bsd/vm/os_bsd.cpp Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/src/os/bsd/vm/os_bsd.cpp Mon Sep 15 15:28:43 2014 +0200
@@ -3814,11 +3814,6 @@
return true;
}
-ATTRIBUTE_PRINTF(3, 0)
-int local_vsnprintf(char* buf, size_t count, const char* format, va_list args) {
- return ::vsnprintf(buf, count, format, args);
-}
-
// Is a (classpath) directory empty?
bool os::dir_is_empty(const char* path) {
DIR *dir = NULL;
--- a/hotspot/src/os/linux/vm/os_linux.cpp Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Mon Sep 15 15:28:43 2014 +0200
@@ -5041,10 +5041,6 @@
return true;
}
-int local_vsnprintf(char* buf, size_t count, const char* format, va_list args) {
- return ::vsnprintf(buf, count, format, args);
-}
-
// Is a (classpath) directory empty?
bool os::dir_is_empty(const char* path) {
DIR *dir = NULL;
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Mon Sep 15 15:28:43 2014 +0200
@@ -4742,27 +4742,6 @@
bool os::check_heap(bool force) { return true; }
-typedef int (*vsnprintf_t)(char* buf, size_t count, const char* fmt, va_list argptr);
-static vsnprintf_t sol_vsnprintf = NULL;
-
-int local_vsnprintf(char* buf, size_t count, const char* fmt, va_list argptr) {
- if (!sol_vsnprintf) {
- //search for the named symbol in the objects that were loaded after libjvm
- void* where = RTLD_NEXT;
- if ((sol_vsnprintf = CAST_TO_FN_PTR(vsnprintf_t, dlsym(where, "__vsnprintf"))) == NULL)
- sol_vsnprintf = CAST_TO_FN_PTR(vsnprintf_t, dlsym(where, "vsnprintf"));
- if (!sol_vsnprintf){
- //search for the named symbol in the objects that were loaded before libjvm
- where = RTLD_DEFAULT;
- if ((sol_vsnprintf = CAST_TO_FN_PTR(vsnprintf_t, dlsym(where, "__vsnprintf"))) == NULL)
- sol_vsnprintf = CAST_TO_FN_PTR(vsnprintf_t, dlsym(where, "vsnprintf"));
- assert(sol_vsnprintf != NULL, "vsnprintf not found");
- }
- }
- return (*sol_vsnprintf)(buf, count, fmt, argptr);
-}
-
-
// Is a (classpath) directory empty?
bool os::dir_is_empty(const char* path) {
DIR *dir = NULL;
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Mon Sep 15 15:28:43 2014 +0200
@@ -4737,7 +4737,7 @@
}
bool G1PrintRegionLivenessInfoClosure::doHeapRegion(HeapRegion* r) {
- const char* type = "";
+ const char* type = r->get_type_str();
HeapWord* bottom = r->bottom();
HeapWord* end = r->end();
size_t capacity_bytes = r->capacity();
@@ -4748,15 +4748,7 @@
size_t remset_bytes = r->rem_set()->mem_size();
size_t strong_code_roots_bytes = r->rem_set()->strong_code_roots_mem_size();
- if (r->used() == 0) {
- type = "FREE";
- } else if (r->is_survivor()) {
- type = "SURV";
- } else if (r->is_young()) {
- type = "EDEN";
- } else if (r->startsHumongous()) {
- type = "HUMS";
-
+ if (r->startsHumongous()) {
assert(_hum_used_bytes == 0 && _hum_capacity_bytes == 0 &&
_hum_prev_live_bytes == 0 && _hum_next_live_bytes == 0,
"they should have been zeroed after the last time we used them");
@@ -4769,12 +4761,9 @@
&prev_live_bytes, &next_live_bytes);
end = bottom + HeapRegion::GrainWords;
} else if (r->continuesHumongous()) {
- type = "HUMC";
get_hum_bytes(&used_bytes, &capacity_bytes,
&prev_live_bytes, &next_live_bytes);
assert(end == bottom + HeapRegion::GrainWords, "invariant");
- } else {
- type = "OLD";
}
_total_used_bytes += used_bytes;
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Mon Sep 15 15:28:43 2014 +0200
@@ -211,7 +211,10 @@
HeapRegion* next = list->get_next_young_region();
list->set_next_young_region(NULL);
list->uninstall_surv_rate_group();
- list->set_not_young();
+ // This is called before a Full GC and all the non-empty /
+ // non-humongous regions at the end of the Full GC will end up as
+ // old anyway.
+ list->set_old();
list = next;
}
}
@@ -370,7 +373,7 @@
if (curr == NULL)
gclog_or_tty->print_cr(" empty");
while (curr != NULL) {
- gclog_or_tty->print_cr(" "HR_FORMAT", P: "PTR_FORMAT "N: "PTR_FORMAT", age: %4d",
+ gclog_or_tty->print_cr(" "HR_FORMAT", P: "PTR_FORMAT ", N: "PTR_FORMAT", age: %4d",
HR_FORMAT_PARAMS(curr),
curr->prev_top_at_mark_start(),
curr->next_top_at_mark_start(),
@@ -802,6 +805,7 @@
#ifdef ASSERT
for (uint i = first; i < first + obj_regions; ++i) {
HeapRegion* hr = region_at(i);
+ assert(hr->is_free(), "sanity");
assert(hr->is_empty(), "sanity");
assert(is_on_master_free_list(hr), "sanity");
}
@@ -1225,21 +1229,21 @@
public:
bool doHeapRegion(HeapRegion* hr) {
assert(!hr->is_young(), "not expecting to find young regions");
- // We only generate output for non-empty regions.
- if (!hr->is_empty()) {
- if (!hr->isHumongous()) {
- _hr_printer->post_compaction(hr, G1HRPrinter::Old);
- } else if (hr->startsHumongous()) {
- if (hr->region_num() == 1) {
- // single humongous region
- _hr_printer->post_compaction(hr, G1HRPrinter::SingleHumongous);
- } else {
- _hr_printer->post_compaction(hr, G1HRPrinter::StartsHumongous);
- }
+ if (hr->is_free()) {
+ // We only generate output for non-empty regions.
+ } else if (hr->startsHumongous()) {
+ if (hr->region_num() == 1) {
+ // single humongous region
+ _hr_printer->post_compaction(hr, G1HRPrinter::SingleHumongous);
} else {
- assert(hr->continuesHumongous(), "only way to get here");
- _hr_printer->post_compaction(hr, G1HRPrinter::ContinuesHumongous);
+ _hr_printer->post_compaction(hr, G1HRPrinter::StartsHumongous);
}
+ } else if (hr->continuesHumongous()) {
+ _hr_printer->post_compaction(hr, G1HRPrinter::ContinuesHumongous);
+ } else if (hr->is_old()) {
+ _hr_printer->post_compaction(hr, G1HRPrinter::Old);
+ } else {
+ ShouldNotReachHere();
}
return false;
}
@@ -2121,8 +2125,8 @@
// We'll re-use the same region whether the alloc region will
// require BOT updates or not and, if it doesn't, then a non-young
// region will complain that it cannot support allocations without
- // BOT updates. So we'll tag the dummy region as young to avoid that.
- dummy_region->set_young();
+ // BOT updates. So we'll tag the dummy region as eden to avoid that.
+ dummy_region->set_eden();
// Make sure it's full.
dummy_region->set_top(dummy_region->end());
G1AllocRegion::setup(this, dummy_region);
@@ -4031,14 +4035,6 @@
if (_hr_printer.is_active()) {
HeapRegion* hr = g1_policy()->collection_set();
while (hr != NULL) {
- G1HRPrinter::RegionType type;
- if (!hr->is_young()) {
- type = G1HRPrinter::Old;
- } else if (hr->is_survivor()) {
- type = G1HRPrinter::Survivor;
- } else {
- type = G1HRPrinter::Eden;
- }
_hr_printer.cset(hr);
hr = hr->next_in_collection_set();
}
@@ -5448,9 +5444,10 @@
void do_oop(narrowOop* p) { guarantee(false, "Not needed"); }
void do_oop(oop* p) {
oop obj = *p;
+ assert(obj != NULL, "the caller should have filtered out NULL values");
G1CollectedHeap::in_cset_state_t cset_state = _g1->in_cset_state(obj);
- if (obj == NULL || cset_state == G1CollectedHeap::InNeither) {
+ if (cset_state == G1CollectedHeap::InNeither) {
return;
}
if (cset_state == G1CollectedHeap::InCSet) {
@@ -6062,7 +6059,7 @@
FreeRegionList* free_list,
bool par,
bool locked) {
- assert(!hr->isHumongous(), "this is only for non-humongous regions");
+ assert(!hr->is_free(), "the region should not be free");
assert(!hr->is_empty(), "the region should not be empty");
assert(_hrm.is_available(hr->hrm_index()), "region should be committed");
assert(free_list != NULL, "pre-condition");
@@ -6092,14 +6089,14 @@
// We need to read this before we make the region non-humongous,
// otherwise the information will be gone.
uint last_index = hr->last_hc_index();
- hr->set_notHumongous();
+ hr->clear_humongous();
free_region(hr, free_list, par);
uint i = hr->hrm_index() + 1;
while (i < last_index) {
HeapRegion* curr_hr = region_at(i);
assert(curr_hr->continuesHumongous(), "invariant");
- curr_hr->set_notHumongous();
+ curr_hr->clear_humongous();
free_region(curr_hr, free_list, par);
i += 1;
}
@@ -6407,9 +6404,9 @@
if (cur->is_young()) {
cur->set_young_index_in_cset(-1);
}
- cur->set_not_young();
cur->set_evacuation_failed(false);
// The region is now considered to be old.
+ cur->set_old();
_old_set.add(cur);
evacuation_info.increment_collectionset_used_after(cur->used());
}
@@ -6696,16 +6693,15 @@
TearDownRegionSetsClosure(HeapRegionSet* old_set) : _old_set(old_set) { }
bool doHeapRegion(HeapRegion* r) {
- if (r->is_empty()) {
- // We ignore empty regions, we'll empty the free list afterwards
- } else if (r->is_young()) {
- // We ignore young regions, we'll empty the young list afterwards
- } else if (r->isHumongous()) {
+ if (r->is_old()) {
+ _old_set->remove(r);
+ } else {
+ // We ignore free regions, we'll empty the free list afterwards.
+ // We ignore young regions, we'll empty the young list afterwards.
// We ignore humongous regions, we're not tearing down the
- // humongous region set
- } else {
- // The rest should be old
- _old_set->remove(r);
+ // humongous regions set.
+ assert(r->is_free() || r->is_young() || r->isHumongous(),
+ "it cannot be another type");
}
return false;
}
@@ -6755,6 +6751,7 @@
if (r->is_empty()) {
// Add free regions to the free list
+ r->set_free();
_hrm->insert_into_free_list(r);
} else if (!_free_list_only) {
assert(!r->is_young(), "we should not come across young regions");
@@ -6762,7 +6759,11 @@
if (r->isHumongous()) {
// We ignore humongous regions, we left the humongous set unchanged
} else {
- // The rest should be old, add them to the old set
+ // Objects that were compacted would have ended up on regions
+ // that were previously old or free.
+ assert(r->is_free() || r->is_old(), "invariant");
+ // We now consider them old, so register as such.
+ r->set_old();
_old_set->add(r);
}
_total_used += r->used();
@@ -6829,7 +6830,7 @@
void G1CollectedHeap::retire_mutator_alloc_region(HeapRegion* alloc_region,
size_t allocated_bytes) {
assert_heap_locked_or_at_safepoint(true /* should_be_vm_thread */);
- assert(alloc_region->is_young(), "all mutator alloc regions should be young");
+ assert(alloc_region->is_eden(), "all mutator alloc regions should be eden");
g1_policy()->add_region_to_incremental_cset_lhs(alloc_region);
_summary_bytes_used += allocated_bytes;
@@ -6888,6 +6889,7 @@
_hr_printer.alloc(new_alloc_region, G1HRPrinter::Survivor);
check_bitmaps("Survivor Region Allocation", new_alloc_region);
} else {
+ new_alloc_region->set_old();
_hr_printer.alloc(new_alloc_region, G1HRPrinter::Old);
check_bitmaps("Old Region Allocation", new_alloc_region);
}
@@ -6999,9 +7001,11 @@
} else if (hr->is_empty()) {
assert(_hrm->is_free(hr), err_msg("Heap region %u is empty but not on the free list.", hr->hrm_index()));
_free_count.increment(1u, hr->capacity());
- } else {
+ } else if (hr->is_old()) {
assert(hr->containing_set() == _old_set, err_msg("Heap region %u is old but not in the old set.", hr->hrm_index()));
_old_count.increment(1u, hr->capacity());
+ } else {
+ ShouldNotReachHere();
}
return false;
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Mon Sep 15 15:28:43 2014 +0200
@@ -1665,7 +1665,7 @@
// Add the heap region at the head of the non-incremental collection set
void G1CollectorPolicy::add_old_region_to_cset(HeapRegion* hr) {
assert(_inc_cset_build_state == Active, "Precondition");
- assert(!hr->is_young(), "non-incremental add of young region");
+ assert(hr->is_old(), "the region should be old");
assert(!hr->in_collection_set(), "should not already be in the CSet");
hr->set_in_collection_set(true);
@@ -1811,7 +1811,7 @@
// Add the region at the RHS of the incremental cset
void G1CollectorPolicy::add_region_to_incremental_cset_rhs(HeapRegion* hr) {
// We should only ever be appending survivors at the end of a pause
- assert( hr->is_survivor(), "Logic");
+ assert(hr->is_survivor(), "Logic");
// Do the 'common' stuff
add_region_to_incremental_cset_common(hr);
@@ -1829,7 +1829,7 @@
// Add the region to the LHS of the incremental cset
void G1CollectorPolicy::add_region_to_incremental_cset_lhs(HeapRegion* hr) {
// Survivors should be added to the RHS at the end of a pause
- assert(!hr->is_survivor(), "Logic");
+ assert(hr->is_eden(), "Logic");
// Do the 'common' stuff
add_region_to_incremental_cset_common(hr);
@@ -1989,7 +1989,11 @@
HeapRegion* hr = young_list->first_survivor_region();
while (hr != NULL) {
assert(hr->is_survivor(), "badly formed young list");
- hr->set_young();
+ // There is a convention that all the young regions in the CSet
+ // are tagged as "eden", so we do this for the survivors here. We
+ // use the special set_eden_pre_gc() as it doesn't check that the
+ // region is free (which is not the case here).
+ hr->set_eden_pre_gc();
hr = hr->get_next_young_region();
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Mon Sep 15 15:28:43 2014 +0200
@@ -299,13 +299,13 @@
// Accessors
void set_region_eden(HeapRegion* hr, int young_index_in_cset) {
- hr->set_young();
+ hr->set_eden();
hr->install_surv_rate_group(_short_lived_surv_rate_group);
hr->set_young_index_in_cset(young_index_in_cset);
}
void set_region_survivor(HeapRegion* hr, int young_index_in_cset) {
- assert(hr->is_young() && hr->is_survivor(), "pre-condition");
+ assert(hr->is_survivor(), "pre-condition");
hr->install_surv_rate_group(_survivor_surv_rate_group);
hr->set_young_index_in_cset(young_index_in_cset);
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.cpp Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1HotCardCache.cpp Mon Sep 15 15:28:43 2014 +0200
@@ -27,7 +27,6 @@
#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
#include "gc_implementation/g1/g1HotCardCache.hpp"
#include "gc_implementation/g1/g1RemSet.hpp"
-#include "gc_implementation/g1/heapRegion.hpp"
#include "runtime/atomic.inline.hpp"
G1HotCardCache::G1HotCardCache(G1CollectedHeap *g1h):
@@ -136,7 +135,6 @@
}
void G1HotCardCache::reset_card_counts(HeapRegion* hr) {
- assert(!hr->isHumongous(), "Should have been cleared");
_card_counts.clear_region(hr);
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSetSummary.cpp Mon Sep 15 15:28:43 2014 +0200
@@ -259,14 +259,16 @@
size_t code_root_elems = hrrs->strong_code_roots_list_length();
RegionTypeCounter* current = NULL;
- if (r->is_young()) {
+ if (r->is_free()) {
+ current = &_free;
+ } else if (r->is_young()) {
current = &_young;
} else if (r->isHumongous()) {
current = &_humonguous;
- } else if (r->is_empty()) {
- current = &_free;
+ } else if (r->is_old()) {
+ current = &_old;
} else {
- current = &_old;
+ ShouldNotReachHere();
}
current->add(rs_mem_sz, occupied_cards, code_root_mem_sz, code_root_elems);
_all.add(rs_mem_sz, occupied_cards, code_root_mem_sz, code_root_elems);
--- a/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1SATBCardTableModRefBS.hpp Mon Sep 15 15:28:43 2014 +0200
@@ -31,8 +31,6 @@
#include "oops/oop.inline.hpp"
#include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-
class DirtyCardQueueSet;
class G1SATBCardTableLoggingModRefBS;
@@ -180,7 +178,4 @@
void write_ref_array_work(MemRegion mr) { invalidate(mr); }
};
-
-#endif // INCLUDE_ALL_GCS
-
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1SATBCARDTABLEMODREFBS_HPP
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp Mon Sep 15 15:28:43 2014 +0200
@@ -211,8 +211,6 @@
}
void HeapRegion::hr_clear(bool par, bool clear_space, bool locked) {
- assert(_humongous_type == NotHumongous,
- "we should have already filtered out humongous regions");
assert(_humongous_start_region == NULL,
"we should have already filtered out humongous regions");
assert(_end == _orig_end,
@@ -222,7 +220,7 @@
set_young_index_in_cset(-1);
uninstall_surv_rate_group();
- set_young_type(NotYoung);
+ set_free();
reset_pre_dummy_top();
if (!par) {
@@ -273,7 +271,7 @@
assert(top() == bottom(), "should be empty");
assert(bottom() <= new_top && new_top <= new_end, "pre-condition");
- _humongous_type = StartsHumongous;
+ _type.set_starts_humongous();
_humongous_start_region = this;
set_end(new_end);
@@ -287,11 +285,11 @@
assert(top() == bottom(), "should be empty");
assert(first_hr->startsHumongous(), "pre-condition");
- _humongous_type = ContinuesHumongous;
+ _type.set_continues_humongous();
_humongous_start_region = first_hr;
}
-void HeapRegion::set_notHumongous() {
+void HeapRegion::clear_humongous() {
assert(isHumongous(), "pre-condition");
if (startsHumongous()) {
@@ -307,7 +305,6 @@
}
assert(capacity() == HeapRegion::GrainBytes, "pre-condition");
- _humongous_type = NotHumongous;
_humongous_start_region = NULL;
}
@@ -327,12 +324,12 @@
MemRegion mr) :
G1OffsetTableContigSpace(sharedOffsetArray, mr),
_hrm_index(hrm_index),
- _humongous_type(NotHumongous), _humongous_start_region(NULL),
+ _humongous_start_region(NULL),
_in_collection_set(false),
_next_in_special_set(NULL), _orig_end(NULL),
_claimed(InitialClaimValue), _evacuation_failed(false),
_prev_marked_bytes(0), _next_marked_bytes(0), _gc_efficiency(0.0),
- _young_type(NotYoung), _next_young_region(NULL),
+ _next_young_region(NULL),
_next_dirty_cards_region(NULL), _next(NULL), _prev(NULL),
#ifdef ASSERT
_containing_set(NULL),
@@ -686,26 +683,11 @@
void HeapRegion::print() const { print_on(gclog_or_tty); }
void HeapRegion::print_on(outputStream* st) const {
- if (isHumongous()) {
- if (startsHumongous())
- st->print(" HS");
- else
- st->print(" HC");
- } else {
- st->print(" ");
- }
+ st->print(" %2s", get_short_type_str());
if (in_collection_set())
st->print(" CS");
else
st->print(" ");
- if (is_young())
- st->print(is_survivor() ? " SU" : " Y ");
- else
- st->print(" ");
- if (is_empty())
- st->print(" F");
- else
- st->print(" ");
st->print(" TS %5d", _gc_time_stamp);
st->print(" PTAMS "PTR_FORMAT" NTAMS "PTR_FORMAT,
prev_top_at_mark_start(), next_top_at_mark_start());
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp Mon Sep 15 15:28:43 2014 +0200
@@ -27,6 +27,7 @@
#include "gc_implementation/g1/g1BlockOffsetTable.hpp"
#include "gc_implementation/g1/g1_specialized_oop_closures.hpp"
+#include "gc_implementation/g1/heapRegionType.hpp"
#include "gc_implementation/g1/survRateGroup.hpp"
#include "gc_implementation/shared/ageTable.hpp"
#include "gc_implementation/shared/spaceDecorator.hpp"
@@ -34,8 +35,6 @@
#include "memory/watermark.hpp"
#include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-
// A HeapRegion is the smallest piece of a G1CollectedHeap that
// can be collected independently.
@@ -55,10 +54,7 @@
#define HR_FORMAT "%u:(%s)["PTR_FORMAT","PTR_FORMAT","PTR_FORMAT"]"
#define HR_FORMAT_PARAMS(_hr_) \
(_hr_)->hrm_index(), \
- (_hr_)->is_survivor() ? "S" : (_hr_)->is_young() ? "E" : \
- (_hr_)->startsHumongous() ? "HS" : \
- (_hr_)->continuesHumongous() ? "HC" : \
- !(_hr_)->is_empty() ? "O" : "F", \
+ (_hr_)->get_short_type_str(), \
p2i((_hr_)->bottom()), p2i((_hr_)->top()), p2i((_hr_)->end())
// sentinel value for hrm_index
@@ -215,12 +211,6 @@
friend class VMStructs;
private:
- enum HumongousType {
- NotHumongous = 0,
- StartsHumongous,
- ContinuesHumongous
- };
-
// The remembered set for this region.
// (Might want to make this "inline" later, to avoid some alloc failure
// issues.)
@@ -232,7 +222,8 @@
// The index of this region in the heap region sequence.
uint _hrm_index;
- HumongousType _humongous_type;
+ HeapRegionType _type;
+
// For a humongous region, region in which it starts.
HeapRegion* _humongous_start_region;
// For the start region of a humongous sequence, it's original end().
@@ -274,13 +265,6 @@
// The calculated GC efficiency of the region.
double _gc_efficiency;
- enum YoungType {
- NotYoung, // a region is not young
- Young, // a region is young
- Survivor // a region is young and it contains survivors
- };
-
- volatile YoungType _young_type;
int _young_index_in_cset;
SurvRateGroup* _surv_rate_group;
int _age_index;
@@ -305,12 +289,6 @@
_next_top_at_mark_start = bot;
}
- void set_young_type(YoungType new_type) {
- //assert(_young_type != new_type, "setting the same type" );
- // TODO: add more assertions here
- _young_type = new_type;
- }
-
// Cached attributes used in the collection set policy information
// The RSet length that was added to the total value
@@ -430,9 +408,21 @@
_prev_marked_bytes = _next_marked_bytes = 0;
}
- bool isHumongous() const { return _humongous_type != NotHumongous; }
- bool startsHumongous() const { return _humongous_type == StartsHumongous; }
- bool continuesHumongous() const { return _humongous_type == ContinuesHumongous; }
+ const char* get_type_str() const { return _type.get_str(); }
+ const char* get_short_type_str() const { return _type.get_short_str(); }
+
+ bool is_free() const { return _type.is_free(); }
+
+ bool is_young() const { return _type.is_young(); }
+ bool is_eden() const { return _type.is_eden(); }
+ bool is_survivor() const { return _type.is_survivor(); }
+
+ bool isHumongous() const { return _type.is_humongous(); }
+ bool startsHumongous() const { return _type.is_starts_humongous(); }
+ bool continuesHumongous() const { return _type.is_continues_humongous(); }
+
+ bool is_old() const { return _type.is_old(); }
+
// For a humongous region, region in which it starts.
HeapRegion* humongous_start_region() const {
return _humongous_start_region;
@@ -496,7 +486,7 @@
void set_continuesHumongous(HeapRegion* first_hr);
// Unsets the humongous-related fields on the region.
- void set_notHumongous();
+ void clear_humongous();
// If the region has a remembered set, return a pointer to it.
HeapRegionRemSet* rem_set() const {
@@ -623,9 +613,6 @@
void calc_gc_efficiency(void);
double gc_efficiency() { return _gc_efficiency;}
- bool is_young() const { return _young_type != NotYoung; }
- bool is_survivor() const { return _young_type == Survivor; }
-
int young_index_in_cset() const { return _young_index_in_cset; }
void set_young_index_in_cset(int index) {
assert( (index == -1) || is_young(), "pre-condition" );
@@ -677,11 +664,13 @@
}
}
- void set_young() { set_young_type(Young); }
+ void set_free() { _type.set_free(); }
- void set_survivor() { set_young_type(Survivor); }
+ void set_eden() { _type.set_eden(); }
+ void set_eden_pre_gc() { _type.set_eden_pre_gc(); }
+ void set_survivor() { _type.set_survivor(); }
- void set_not_young() { set_young_type(NotYoung); }
+ void set_old() { _type.set_old(); }
// Determine if an object has been allocated since the last
// mark performed by the collector. This returns true iff the object
@@ -809,6 +798,4 @@
bool complete() { return _complete; }
};
-#endif // INCLUDE_ALL_GCS
-
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGION_HPP
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.cpp Mon Sep 15 15:28:43 2014 +0200
@@ -42,7 +42,9 @@
assert(hr->containing_set() == this, err_msg("Inconsistent containing set for %u", hr->hrm_index()));
assert(!hr->is_young(), err_msg("Adding young region %u", hr->hrm_index())); // currently we don't use these sets for young regions
assert(hr->isHumongous() == regions_humongous(), err_msg("Wrong humongous state for region %u and set %s", hr->hrm_index(), name()));
- assert(hr->is_empty() == regions_empty(), err_msg("Wrong empty state for region %u and set %s", hr->hrm_index(), name()));
+ assert(hr->is_free() == regions_free(), err_msg("Wrong free state for region %u and set %s", hr->hrm_index(), name()));
+ assert(!hr->is_free() || hr->is_empty(), err_msg("Free region %u is not empty for set %s", hr->hrm_index(), name()));
+ assert(!hr->is_empty() || hr->is_free(), err_msg("Empty region %u is not free for set %s", hr->hrm_index(), name()));
assert(hr->rem_set()->verify_ready_for_par_iteration(), err_msg("Wrong iteration state %u", hr->hrm_index()));
}
#endif
@@ -85,16 +87,16 @@
out->print_cr("Set: %s ("PTR_FORMAT")", name(), this);
out->print_cr(" Region Assumptions");
out->print_cr(" humongous : %s", BOOL_TO_STR(regions_humongous()));
- out->print_cr(" empty : %s", BOOL_TO_STR(regions_empty()));
+ out->print_cr(" free : %s", BOOL_TO_STR(regions_free()));
out->print_cr(" Attributes");
out->print_cr(" length : %14u", length());
out->print_cr(" total capacity : "SIZE_FORMAT_W(14)" bytes",
total_capacity_bytes());
}
-HeapRegionSetBase::HeapRegionSetBase(const char* name, bool humongous, bool empty, HRSMtSafeChecker* mt_safety_checker)
+HeapRegionSetBase::HeapRegionSetBase(const char* name, bool humongous, bool free, HRSMtSafeChecker* mt_safety_checker)
: _name(name), _verify_in_progress(false),
- _is_humongous(humongous), _is_empty(empty), _mt_safety_checker(mt_safety_checker),
+ _is_humongous(humongous), _is_free(free), _mt_safety_checker(mt_safety_checker),
_count()
{ }
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionSet.hpp Mon Sep 15 15:28:43 2014 +0200
@@ -81,7 +81,7 @@
friend class VMStructs;
private:
bool _is_humongous;
- bool _is_empty;
+ bool _is_free;
HRSMtSafeChecker* _mt_safety_checker;
protected:
@@ -102,9 +102,9 @@
// not. Only used during verification.
bool regions_humongous() { return _is_humongous; }
- // Indicates whether all regions in the set should be empty or
+ // Indicates whether all regions in the set should be free or
// not. Only used during verification.
- bool regions_empty() { return _is_empty; }
+ bool regions_free() { return _is_free; }
void check_mt_safety() {
if (_mt_safety_checker != NULL) {
@@ -114,7 +114,7 @@
virtual void fill_in_ext_msg_extra(hrs_ext_msg* msg) { }
- HeapRegionSetBase(const char* name, bool humongous, bool empty, HRSMtSafeChecker* mt_safety_checker);
+ HeapRegionSetBase(const char* name, bool humongous, bool free, HRSMtSafeChecker* mt_safety_checker);
public:
const char* name() { return _name; }
@@ -171,7 +171,7 @@
do { \
assert(((_set1_)->regions_humongous() == \
(_set2_)->regions_humongous()) && \
- ((_set1_)->regions_empty() == (_set2_)->regions_empty()), \
+ ((_set1_)->regions_free() == (_set2_)->regions_free()), \
hrs_err_msg("the contents of set %s and set %s should match", \
(_set1_)->name(), (_set2_)->name())); \
} while (0)
@@ -184,7 +184,7 @@
class HeapRegionSet : public HeapRegionSetBase {
public:
HeapRegionSet(const char* name, bool humongous, HRSMtSafeChecker* mt_safety_checker):
- HeapRegionSetBase(name, humongous, false /* empty */, mt_safety_checker) { }
+ HeapRegionSetBase(name, humongous, false /* free */, mt_safety_checker) { }
void bulk_remove(const HeapRegionSetCount& removed) {
_count.decrement(removed.length(), removed.capacity());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionType.cpp Mon Sep 15 15:28:43 2014 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014, 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc_implementation/g1/heapRegionType.hpp"
+
+bool HeapRegionType::is_valid(Tag tag) {
+ switch (tag) {
+ case FreeTag:
+ case EdenTag:
+ case SurvTag:
+ case HumStartsTag:
+ case HumContTag:
+ case OldTag:
+ return true;
+ }
+ return false;
+}
+
+const char* HeapRegionType::get_str() const {
+ hrt_assert_is_valid(_tag);
+ switch (_tag) {
+ case FreeTag: return "FREE";
+ case EdenTag: return "EDEN";
+ case SurvTag: return "SURV";
+ case HumStartsTag: return "HUMS";
+ case HumContTag: return "HUMC";
+ case OldTag: return "OLD";
+ }
+ ShouldNotReachHere();
+ // keep some compilers happy
+ return NULL;
+}
+
+const char* HeapRegionType::get_short_str() const {
+ hrt_assert_is_valid(_tag);
+ switch (_tag) {
+ case FreeTag: return "F";
+ case EdenTag: return "E";
+ case SurvTag: return "S";
+ case HumStartsTag: return "HS";
+ case HumContTag: return "HC";
+ case OldTag: return "O";
+ }
+ ShouldNotReachHere();
+ // keep some compilers happy
+ return NULL;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionType.hpp Mon Sep 15 15:28:43 2014 +0200
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2014, 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_VM_GC_IMPLEMENTATION_G1_HEAPREGIONTYPE_HPP
+#define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONTYPE_HPP
+
+#include "memory/allocation.hpp"
+
+#define hrt_assert_is_valid(tag) \
+ assert(is_valid((tag)), err_msg("invalid HR type: %u", (uint) (tag)))
+
+class HeapRegionType VALUE_OBJ_CLASS_SPEC {
+private:
+ // We encode the value of the heap region type so the generation can be
+ // determined quickly. The tag is split into two parts:
+ //
+ // major type (young, humongous) : top N-1 bits
+ // minor type (eden / survivor, starts / cont hum, etc.) : bottom 1 bit
+ //
+ // If there's need to increase the number of minor types in the
+ // future, we'll have to increase the size of the latter and hence
+ // decrease the size of the former.
+ //
+ // 0000 0 [ 0] Free
+ //
+ // 0001 0 Young Mask
+ // 0001 0 [ 2] Eden
+ // 0001 1 [ 3] Survivor
+ //
+ // 0010 0 Humongous Mask
+ // 0010 0 [ 4] Humongous Starts
+ // 0010 1 [ 5] Humongous Continues
+ //
+ // 01000 [ 8] Old
+ typedef enum {
+ FreeTag = 0,
+
+ YoungMask = 2,
+ EdenTag = YoungMask,
+ SurvTag = YoungMask + 1,
+
+ HumMask = 4,
+ HumStartsTag = HumMask,
+ HumContTag = HumMask + 1,
+
+ OldTag = 8
+ } Tag;
+
+ volatile Tag _tag;
+
+ static bool is_valid(Tag tag);
+
+ Tag get() const {
+ hrt_assert_is_valid(_tag);
+ return _tag;
+ }
+
+ // Sets the type to 'tag'.
+ void set(Tag tag) {
+ hrt_assert_is_valid(tag);
+ hrt_assert_is_valid(_tag);
+ _tag = tag;
+ }
+
+ // Sets the type to 'tag', expecting the type to be 'before'. This
+ // is available for when we want to add sanity checking to the type
+ // transition.
+ void set_from(Tag tag, Tag before) {
+ hrt_assert_is_valid(tag);
+ hrt_assert_is_valid(before);
+ hrt_assert_is_valid(_tag);
+ assert(_tag == before,
+ err_msg("HR tag: %u, expected: %u new tag; %u", _tag, before, tag));
+ _tag = tag;
+ }
+
+public:
+ // Queries
+
+ bool is_free() const { return get() == FreeTag; }
+
+ bool is_young() const { return (get() & YoungMask) != 0; }
+ bool is_eden() const { return get() == EdenTag; }
+ bool is_survivor() const { return get() == SurvTag; }
+
+ bool is_humongous() const { return (get() & HumMask) != 0; }
+ bool is_starts_humongous() const { return get() == HumStartsTag; }
+ bool is_continues_humongous() const { return get() == HumContTag; }
+
+ bool is_old() const { return get() == OldTag; }
+
+ // Setters
+
+ void set_free() { set(FreeTag); }
+
+ void set_eden() { set_from(EdenTag, FreeTag); }
+ void set_eden_pre_gc() { set_from(EdenTag, SurvTag); }
+ void set_survivor() { set_from(SurvTag, FreeTag); }
+
+ void set_starts_humongous() { set_from(HumStartsTag, FreeTag); }
+ void set_continues_humongous() { set_from(HumContTag, FreeTag); }
+
+ void set_old() { set(OldTag); }
+
+ // Misc
+
+ const char* get_str() const;
+ const char* get_short_str() const;
+
+ HeapRegionType() : _tag(FreeTag) { hrt_assert_is_valid(_tag); }
+};
+
+#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONTYPE_HPP
--- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp Mon Sep 15 15:28:43 2014 +0200
@@ -66,6 +66,9 @@
#ifndef ATTRIBUTE_PRINTF
#define ATTRIBUTE_PRINTF(fmt, vargs)
#endif
+#ifndef ATTRIBUTE_SCANF
+#define ATTRIBUTE_SCANF(fmt, vargs)
+#endif
#include "utilities/macros.hpp"
--- a/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/src/share/vm/utilities/globalDefinitions_gcc.hpp Mon Sep 15 15:28:43 2014 +0200
@@ -271,15 +271,16 @@
#define PRAGMA_IMPLEMENTATION #pragma implementation
#define VALUE_OBJ_CLASS_SPEC
-#ifndef ATTRIBUTE_PRINTF
// Diagnostic pragmas like the ones defined below in PRAGMA_FORMAT_NONLITERAL_IGNORED
// were only introduced in GCC 4.2. Because we have no other possibility to ignore
// these warnings for older versions of GCC, we simply don't decorate our printf-style
// functions with __attribute__(format) in that case.
#if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) || (__GNUC__ > 4)
+#ifndef ATTRIBUTE_PRINTF
#define ATTRIBUTE_PRINTF(fmt,vargs) __attribute__((format(printf, fmt, vargs)))
-#else
-#define ATTRIBUTE_PRINTF(fmt,vargs)
+#endif
+#ifndef ATTRIBUTE_SCANF
+#define ATTRIBUTE_SCANF(fmt,vargs) __attribute__((format(scanf, fmt, vargs)))
#endif
#endif
--- a/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/src/share/vm/utilities/globalDefinitions_sparcWorks.hpp Mon Sep 15 15:28:43 2014 +0200
@@ -265,14 +265,6 @@
inline int wcslen(const jchar* x) { return wcslen((const wchar_t*)x); }
-
-// Misc
-// NOTE: This one leads to an infinite recursion on Linux
-#ifndef LINUX
-int local_vsnprintf(char* buf, size_t count, const char* fmt, va_list argptr);
-#define vsnprintf local_vsnprintf
-#endif
-
// Portability macros
#define PRAGMA_INTERFACE
#define PRAGMA_IMPLEMENTATION
--- a/hotspot/test/gc/g1/TestHumongousShrinkHeap.java Fri Sep 12 04:22:19 2014 -0700
+++ b/hotspot/test/gc/g1/TestHumongousShrinkHeap.java Mon Sep 15 15:28:43 2014 +0200
@@ -26,7 +26,7 @@
* @bug 8036025 8056043
* @summary Verify that heap shrinks after GC in the presence of fragmentation due to humongous objects
* @library /testlibrary
- * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=50 -XX:+UseG1GC -XX:G1HeapRegionSize=1M -verbose:gc TestHumongousShrinkHeap
+ * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=12 -XX:+UseG1GC -XX:G1HeapRegionSize=1M -verbose:gc TestHumongousShrinkHeap
*/
import java.lang.management.ManagementFactory;
@@ -41,12 +41,24 @@
public static final String MIN_FREE_RATIO_FLAG_NAME = "MinHeapFreeRatio";
public static final String MAX_FREE_RATIO_FLAG_NAME = "MaxHeapFreeRatio";
- private static final ArrayList<ArrayList<byte[]>> garbage = new ArrayList<>();
- private static final int PAGE_SIZE = 1024 * 1024; // 1M
- private static final int PAGES_NUM = 5;
+ private static final List<List<byte[]>> garbage = new ArrayList();
+ private static final int REGION_SIZE = 1024 * 1024; // 1M
+ private static final int LISTS_COUNT = 10;
+ private static final int HUMON_SIZE = Math.round(.9f * REGION_SIZE);
+ private static final long AVAILABLE_MEMORY
+ = Runtime.getRuntime().freeMemory();
+ private static final int HUMON_COUNT
+ = (int) ((AVAILABLE_MEMORY / HUMON_SIZE)
+ / LISTS_COUNT);
public static void main(String[] args) {
+ System.out.format("Running with %s max heap size. "
+ + "Will allocate humongous object of %s size %d times.%n",
+ MemoryUsagePrinter.humanReadableByteCount(AVAILABLE_MEMORY, false),
+ MemoryUsagePrinter.humanReadableByteCount(HUMON_SIZE, false),
+ HUMON_COUNT
+ );
new TestHumongousShrinkHeap().test();
}
@@ -54,8 +66,8 @@
System.gc();
MemoryUsagePrinter.printMemoryUsage("init");
- eat();
- MemoryUsagePrinter.printMemoryUsage("eaten");
+ allocate();
+ MemoryUsagePrinter.printMemoryUsage("allocated");
MemoryUsage muFull = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
free();
@@ -72,15 +84,12 @@
));
}
- private void eat() {
- int HumongousObjectSize = Math.round(.9f * PAGE_SIZE);
- System.out.println("Will allocate objects of size=" +
- MemoryUsagePrinter.humanReadableByteCount(HumongousObjectSize, true));
+ private void allocate() {
- for (int i = 0; i < PAGES_NUM; i++) {
- ArrayList<byte[]> stuff = new ArrayList<>();
- eatList(stuff, 100, HumongousObjectSize);
- MemoryUsagePrinter.printMemoryUsage("eat #" + i);
+ for (int i = 0; i < LISTS_COUNT; i++) {
+ List<byte[]> stuff = new ArrayList();
+ allocateList(stuff, HUMON_COUNT, HUMON_SIZE);
+ MemoryUsagePrinter.printMemoryUsage("allocate #" + (i+1));
garbage.add(stuff);
}
}
@@ -90,12 +99,12 @@
garbage.subList(0, garbage.size() - 1).clear();
// do not free last one element from last list
- ArrayList stuff = garbage.get(garbage.size() - 1);
+ List stuff = garbage.get(garbage.size() - 1);
stuff.subList(0, stuff.size() - 1).clear();
System.gc();
}
- private static void eatList(List garbage, int count, int size) {
+ private static void allocateList(List garbage, int count, int size) {
for (int i = 0; i < count; i++) {
garbage.add(new byte[size]);
}
@@ -122,9 +131,9 @@
float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted();
System.out.format("[%-24s] init: %-7s, used: %-7s, comm: %-7s, freeRatio ~= %.1f%%%n",
label,
- humanReadableByteCount(memusage.getInit(), true),
- humanReadableByteCount(memusage.getUsed(), true),
- humanReadableByteCount(memusage.getCommitted(), true),
+ humanReadableByteCount(memusage.getInit(), false),
+ humanReadableByteCount(memusage.getUsed(), false),
+ humanReadableByteCount(memusage.getCommitted(), false),
freeratio * 100
);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/g1/TestShrinkDefragmentedHeap.java Mon Sep 15 15:28:43 2014 +0200
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+/**
+ * @test TestShrinkDefragmentedHeap
+ * @bug 8038423
+ * @summary Verify that heap shrinks after GC in the presence of fragmentation due to humongous objects
+ * 1. allocate small objects mixed with humongous ones
+ * "ssssHssssHssssHssssHssssHssssHssssH"
+ * 2. release all allocated object except the last humongous one
+ * "..................................H"
+ * 3. invoke gc and check that memory returned to the system (amount of committed memory got down)
+ *
+ * @library /testlibrary
+ */
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryUsage;
+import java.util.ArrayList;
+import java.util.List;
+import sun.management.ManagementFactoryHelper;
+import static com.oracle.java.testlibrary.Asserts.*;
+import com.oracle.java.testlibrary.ProcessTools;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+public class TestShrinkDefragmentedHeap {
+ // Since we store all the small objects, they become old and old regions are also allocated at the bottom of the heap
+ // together with humongous regions. So if there are a lot of old regions in the lower part of the heap,
+ // the humongous regions will be allocated in the upper part of the heap anyway.
+ // To avoid this the Eden needs to be big enough to fit all the small objects.
+ private static final int INITIAL_HEAP_SIZE = 200 * 1024 * 1024;
+ private static final int MINIMAL_YOUNG_SIZE = 190 * 1024 * 1024;
+ private static final int REGION_SIZE = 1 * 1024 * 1024;
+
+ public static void main(String[] args) throws Exception, Throwable {
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+ "-XX:InitialHeapSize=" + INITIAL_HEAP_SIZE,
+ "-Xmn" + MINIMAL_YOUNG_SIZE,
+ "-XX:MinHeapFreeRatio=10",
+ "-XX:MaxHeapFreeRatio=11",
+ "-XX:+UseG1GC",
+ "-XX:G1HeapRegionSize=" + REGION_SIZE,
+ "-verbose:gc",
+ GCTest.class.getName()
+ );
+
+ OutputAnalyzer output = ProcessTools.executeProcess(pb);
+ output.shouldHaveExitValue(0);
+ }
+
+ static class GCTest {
+
+ private static final String MIN_FREE_RATIO_FLAG_NAME = "MinHeapFreeRatio";
+ private static final String MAX_FREE_RATIO_FLAG_NAME = "MaxHeapFreeRatio";
+ private static final String NEW_SIZE_FLAG_NAME = "NewSize";
+
+ private static final ArrayList<ArrayList<byte[]>> garbage = new ArrayList<>();
+
+ private static final int SMALL_OBJS_SIZE = 10 * 1024; // 10kB
+ private static final int SMALL_OBJS_COUNT = MINIMAL_YOUNG_SIZE / (SMALL_OBJS_SIZE-1);
+ private static final int ALLOCATE_COUNT = 3;
+ // try to put all humongous object into gap between min young size and initial heap size
+ // to avoid implicit GCs
+ private static final int HUMONG_OBJS_SIZE = (int) Math.max(
+ (INITIAL_HEAP_SIZE - MINIMAL_YOUNG_SIZE) / ALLOCATE_COUNT / 4,
+ REGION_SIZE * 1.1
+ );
+
+ private static final long initialHeapSize = getHeapMemoryUsage().getUsed();
+
+ public static void main(String[] args) throws InterruptedException {
+ new GCTest().test();
+ }
+
+ private void test() throws InterruptedException {
+ MemoryUsagePrinter.printMemoryUsage("init");
+
+ allocate();
+ System.gc();
+ MemoryUsage muFull = getHeapMemoryUsage();
+ MemoryUsagePrinter.printMemoryUsage("allocated");
+
+ free();
+ //Thread.sleep(1000); // sleep before measures due lags in JMX
+ MemoryUsage muFree = getHeapMemoryUsage();
+ MemoryUsagePrinter.printMemoryUsage("free");
+
+ assertLessThan(muFree.getCommitted(), muFull.getCommitted(), prepareMessageCommittedIsNotLess() );
+ }
+
+ private void allocate() {
+ System.out.format("Will allocate objects of small size = %s and humongous size = %s",
+ MemoryUsagePrinter.humanReadableByteCount(SMALL_OBJS_SIZE, false),
+ MemoryUsagePrinter.humanReadableByteCount(HUMONG_OBJS_SIZE, false)
+ );
+
+ for (int i = 0; i < ALLOCATE_COUNT; i++) {
+ ArrayList<byte[]> stuff = new ArrayList<>();
+ allocateList(stuff, SMALL_OBJS_COUNT / ALLOCATE_COUNT, SMALL_OBJS_SIZE);
+ garbage.add(stuff);
+
+ ArrayList<byte[]> humongousStuff = new ArrayList<>();
+ allocateList(humongousStuff, 4, HUMONG_OBJS_SIZE);
+ garbage.add(humongousStuff);
+ }
+ }
+
+ private void free() {
+ // do not free last one list
+ garbage.subList(0, garbage.size() - 1).clear();
+
+ // do not free last one element from last list
+ ArrayList stuff = garbage.get(garbage.size() - 1);
+ if (stuff.size() > 1) {
+ stuff.subList(0, stuff.size() - 1).clear();
+ }
+ System.gc();
+ }
+
+ private String prepareMessageCommittedIsNotLess() {
+ return String.format(
+ "committed free heap size is not less than committed full heap size, heap hasn't been shrunk?%n"
+ + "%s = %s%n%s = %s",
+ MIN_FREE_RATIO_FLAG_NAME,
+ ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MIN_FREE_RATIO_FLAG_NAME).getValue(),
+ MAX_FREE_RATIO_FLAG_NAME,
+ ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MAX_FREE_RATIO_FLAG_NAME).getValue()
+ );
+ }
+
+ private static void allocateList(List garbage, int count, int size) {
+ for (int i = 0; i < count; i++) {
+ garbage.add(new byte[size]);
+ }
+ }
+ }
+
+ static MemoryUsage getHeapMemoryUsage() {
+ return ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
+ }
+
+ /**
+ * Prints memory usage to standard output
+ */
+ static class MemoryUsagePrinter {
+
+ public static String humanReadableByteCount(long bytes, boolean si) {
+ int unit = si ? 1000 : 1024;
+ if (bytes < unit) {
+ return bytes + " B";
+ }
+ int exp = (int) (Math.log(bytes) / Math.log(unit));
+ String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i");
+ return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
+ }
+
+ public static void printMemoryUsage(String label) {
+ MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
+ float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted();
+ System.out.format("[%-24s] init: %-7s, used: %-7s, comm: %-7s, freeRatio ~= %.1f%%%n",
+ label,
+ humanReadableByteCount(memusage.getInit(), false),
+ humanReadableByteCount(memusage.getUsed(), false),
+ humanReadableByteCount(memusage.getCommitted(), false),
+ freeratio * 100
+ );
+ }
+ }
+}