This commit is contained in:
Jon Masamitsu 2008-07-28 15:30:23 -07:00
commit b8633a3b01
46 changed files with 1401 additions and 256 deletions

View File

@ -2278,7 +2278,7 @@ void os::Linux::libnuma_init() {
dlsym(RTLD_DEFAULT, "sched_getcpu")));
if (sched_getcpu() != -1) { // Does it work?
void *handle = dlopen("libnuma.so", RTLD_LAZY);
void *handle = dlopen("libnuma.so.1", RTLD_LAZY);
if (handle != NULL) {
set_numa_node_to_cpus(CAST_TO_FN_PTR(numa_node_to_cpus_func_t,
dlsym(handle, "numa_node_to_cpus")));

View File

@ -2658,6 +2658,12 @@ size_t os::numa_get_leaf_groups(int *ids, size_t size) {
top += r;
cur++;
}
if (bottom == 0) {
// Handle a situation, when the OS reports no memory available.
// Assume UMA architecture.
ids[0] = 0;
return 1;
}
return bottom;
}
@ -4581,7 +4587,7 @@ void os::Solaris::synchronization_init() {
}
void os::Solaris::liblgrp_init() {
void *handle = dlopen("liblgrp.so", RTLD_LAZY);
void *handle = dlopen("liblgrp.so.1", RTLD_LAZY);
if (handle != NULL) {
os::Solaris::set_lgrp_home(CAST_TO_FN_PTR(lgrp_home_func_t, dlsym(handle, "lgrp_home")));
os::Solaris::set_lgrp_init(CAST_TO_FN_PTR(lgrp_init_func_t, dlsym(handle, "lgrp_init")));

View File

@ -71,8 +71,15 @@ TreeList* TreeList::as_TreeList(TreeChunk* tc) {
TreeList* TreeList::as_TreeList(HeapWord* addr, size_t size) {
TreeChunk* tc = (TreeChunk*) addr;
assert(size >= sizeof(TreeChunk), "Chunk is too small for a TreeChunk");
assert(tc->size() == 0 && tc->prev() == NULL && tc->next() == NULL,
"Space should be clear");
// The space in the heap will have been mangled initially but
// is not remangled when a free chunk is returned to the free list
// (since it is used to maintain the chunk on the free list).
assert((ZapUnusedHeapArea &&
SpaceMangler::is_mangled((HeapWord*) tc->size_addr()) &&
SpaceMangler::is_mangled((HeapWord*) tc->prev_addr()) &&
SpaceMangler::is_mangled((HeapWord*) tc->next_addr())) ||
(tc->size() == 0 && tc->prev() == NULL && tc->next() == NULL),
"Space should be clear or mangled");
tc->setSize(size);
tc->linkPrev(NULL);
tc->linkNext(NULL);

View File

@ -54,7 +54,7 @@ CompactibleFreeListSpace::CompactibleFreeListSpace(BlockOffsetSharedArray* bs,
_collector(NULL)
{
_bt.set_space(this);
initialize(mr, true);
initialize(mr, SpaceDecorator::Clear, SpaceDecorator::Mangle);
// We have all of "mr", all of which we place in the dictionary
// as one big chunk. We'll need to decide here which of several
// possible alternative dictionary implementations to use. For

View File

@ -22,7 +22,6 @@
*
*/
// A FreeBlockDictionary is an abstract superclass that will allow
// a number of alternative implementations in the future.
class FreeBlockDictionary: public CHeapObj {

View File

@ -85,6 +85,8 @@ class FreeChunk VALUE_OBJ_CLASS_SPEC {
}
debug_only(void* prev_addr() const { return (void*)&_prev; })
debug_only(void* next_addr() const { return (void*)&_next; })
debug_only(void* size_addr() const { return (void*)&_size; })
size_t size() const volatile {
LP64_ONLY(if (UseCompressedOops) return mark()->get_size(); else )

View File

@ -28,6 +28,7 @@ binaryTreeDictionary.cpp allocationStats.hpp
binaryTreeDictionary.cpp binaryTreeDictionary.hpp
binaryTreeDictionary.cpp globals.hpp
binaryTreeDictionary.cpp ostream.hpp
binaryTreeDictionary.cpp spaceDecorator.hpp
binaryTreeDictionary.hpp freeBlockDictionary.hpp
binaryTreeDictionary.hpp freeList.hpp
@ -114,6 +115,7 @@ compactibleFreeListSpace.cpp java.hpp
compactibleFreeListSpace.cpp liveRange.hpp
compactibleFreeListSpace.cpp oop.inline.hpp
compactibleFreeListSpace.cpp resourceArea.hpp
compactibleFreeListSpace.cpp spaceDecorator.hpp
compactibleFreeListSpace.cpp universe.inline.hpp
compactibleFreeListSpace.cpp vmThread.hpp

View File

@ -32,6 +32,7 @@ asParNewGeneration.cpp defNewGeneration.inline.hpp
asParNewGeneration.cpp oop.pcgc.inline.hpp
asParNewGeneration.cpp parNewGeneration.hpp
asParNewGeneration.cpp referencePolicy.hpp
asParNewGeneration.cpp spaceDecorator.hpp
parCardTableModRefBS.cpp allocation.inline.hpp
parCardTableModRefBS.cpp cardTableModRefBS.hpp
@ -75,6 +76,7 @@ parNewGeneration.cpp referencePolicy.hpp
parNewGeneration.cpp resourceArea.hpp
parNewGeneration.cpp sharedHeap.hpp
parNewGeneration.cpp space.hpp
parNewGeneration.cpp spaceDecorator.hpp
parNewGeneration.cpp workgroup.hpp
parNewGeneration.hpp defNewGeneration.hpp

View File

@ -61,6 +61,7 @@ asPSYoungGen.hpp objectStartArray.hpp
asPSYoungGen.hpp spaceCounters.hpp
asPSYoungGen.hpp psVirtualspace.hpp
asPSYoungGen.hpp psYoungGen.hpp
asPSYoungGen.hpp spaceDecorator.hpp
asPSYoungGen.cpp gcUtil.hpp
asPSYoungGen.cpp java.hpp
@ -70,6 +71,7 @@ asPSYoungGen.cpp psMarkSweepDecorator.hpp
asPSYoungGen.cpp psScavenge.hpp
asPSYoungGen.cpp asPSYoungGen.hpp
asPSYoungGen.cpp psYoungGen.hpp
asPSYoungGen.cpp spaceDecorator.hpp
cardTableExtension.cpp cardTableExtension.hpp
cardTableExtension.cpp gcTaskManager.hpp
@ -225,6 +227,7 @@ psMarkSweep.cpp psYoungGen.hpp
psMarkSweep.cpp referencePolicy.hpp
psMarkSweep.cpp referenceProcessor.hpp
psMarkSweep.cpp safepoint.hpp
psMarkSweep.cpp spaceDecorator.hpp
psMarkSweep.cpp symbolTable.hpp
psMarkSweep.cpp systemDictionary.hpp
psMarkSweep.cpp vmThread.hpp
@ -239,6 +242,7 @@ psMarkSweepDecorator.cpp oop.inline.hpp
psMarkSweepDecorator.cpp parallelScavengeHeap.hpp
psMarkSweepDecorator.cpp psMarkSweep.hpp
psMarkSweepDecorator.cpp psMarkSweepDecorator.hpp
psMarkSweepDecorator.cpp spaceDecorator.hpp
psMarkSweepDecorator.cpp systemDictionary.hpp
psMarkSweepDecorator.hpp mutableSpace.hpp
@ -290,6 +294,7 @@ psOldGen.cpp oop.inline.hpp
psOldGen.cpp parallelScavengeHeap.hpp
psOldGen.cpp psMarkSweepDecorator.hpp
psOldGen.cpp psOldGen.hpp
psOldGen.cpp spaceDecorator.hpp
psOldGen.hpp psGenerationCounters.hpp
psOldGen.hpp mutableSpace.hpp
@ -351,6 +356,7 @@ psScavenge.cpp psTasks.hpp
psScavenge.cpp referencePolicy.hpp
psScavenge.cpp referenceProcessor.hpp
psScavenge.cpp resourceArea.hpp
psScavenge.cpp spaceDecorator.hpp
psScavenge.cpp threadCritical.hpp
psScavenge.cpp vmThread.hpp
psScavenge.cpp vm_operations.hpp
@ -420,6 +426,7 @@ psYoungGen.cpp psMarkSweepDecorator.hpp
psYoungGen.cpp psScavenge.hpp
psYoungGen.cpp psYoungGen.hpp
psYoungGen.cpp mutableNUMASpace.hpp
psYoungGen.cpp spaceDecorator.hpp
psYoungGen.hpp psGenerationCounters.hpp
psYoungGen.hpp mutableSpace.hpp

View File

@ -56,6 +56,7 @@ markSweep.inline.hpp psParallelCompact.hpp
mutableNUMASpace.cpp mutableNUMASpace.hpp
mutableNUMASpace.cpp oop.inline.hpp
mutableNUMASpace.cpp sharedHeap.hpp
mutableNUMASpace.cpp spaceDecorator.hpp
mutableNUMASpace.cpp thread_<os_family>.inline.hpp
mutableNUMASpace.hpp mutableSpace.hpp
@ -64,6 +65,7 @@ mutableNUMASpace.hpp gcUtil.hpp
mutableSpace.cpp mutableSpace.hpp
mutableSpace.cpp oop.inline.hpp
mutableSpace.cpp safepoint.hpp
mutableSpace.cpp spaceDecorator.hpp
mutableSpace.cpp thread.hpp
spaceCounters.cpp resourceArea.hpp

View File

@ -162,10 +162,9 @@ bool ASParNewGeneration::resize_generation(size_t eden_size,
// Grow the generation
size_t change = desired_size - orig_size;
assert(change % alignment == 0, "just checking");
if (!virtual_space()->expand_by(change)) {
if (expand(change)) {
return false; // Error if we fail to resize!
}
size_changed = true;
} else if (desired_size < orig_size) {
size_t desired_change = orig_size - desired_size;
@ -222,7 +221,9 @@ void ASParNewGeneration::reset_survivors_after_shrink() {
// Was there a shrink of the survivor space?
if (new_end < to()->end()) {
MemRegion mr(to()->bottom(), new_end);
to()->initialize(mr, false /* clear */);
to()->initialize(mr,
SpaceDecorator::DontClear,
SpaceDecorator::DontMangle);
}
}
}
@ -322,9 +323,7 @@ void ASParNewGeneration::resize_spaces(size_t requested_eden_size,
pointer_delta(from_start, eden_start, sizeof(char)));
}
// tty->print_cr("eden_size before: " SIZE_FORMAT, eden_size);
eden_size = align_size_down(eden_size, alignment);
// tty->print_cr("eden_size after: " SIZE_FORMAT, eden_size);
eden_end = eden_start + eden_size;
assert(eden_end >= eden_start, "addition overflowed")
@ -501,11 +500,31 @@ void ASParNewGeneration::resize_spaces(size_t requested_eden_size,
size_t old_from = from()->capacity();
size_t old_to = to()->capacity();
// If not clearing the spaces, do some checking to verify that
// the spaces are already mangled.
// Must check mangling before the spaces are reshaped. Otherwise,
// the bottom or end of one space may have moved into another
// a failure of the check may not correctly indicate which space
// is not properly mangled.
if (ZapUnusedHeapArea) {
HeapWord* limit = (HeapWord*) virtual_space()->high();
eden()->check_mangled_unused_area(limit);
from()->check_mangled_unused_area(limit);
to()->check_mangled_unused_area(limit);
}
// The call to initialize NULL's the next compaction space
eden()->initialize(edenMR, true);
eden()->initialize(edenMR,
SpaceDecorator::Clear,
SpaceDecorator::DontMangle);
eden()->set_next_compaction_space(from());
to()->initialize(toMR , true);
from()->initialize(fromMR, false); // Note, not cleared!
to()->initialize(toMR ,
SpaceDecorator::Clear,
SpaceDecorator::DontMangle);
from()->initialize(fromMR,
SpaceDecorator::DontClear,
SpaceDecorator::DontMangle);
assert(from()->top() == old_from_top, "from top changed!");

View File

@ -727,7 +727,7 @@ void ParNewGeneration::collect(bool full,
SpecializationStats::clear();
age_table()->clear();
to()->clear();
to()->clear(SpaceDecorator::Mangle);
gch->save_marks();
assert(workers != NULL, "Need parallel worker threads.");
@ -793,8 +793,18 @@ void ParNewGeneration::collect(bool full,
}
if (!promotion_failed()) {
// Swap the survivor spaces.
eden()->clear();
from()->clear();
eden()->clear(SpaceDecorator::Mangle);
from()->clear(SpaceDecorator::Mangle);
if (ZapUnusedHeapArea) {
// This is now done here because of the piece-meal mangling which
// can check for valid mangling at intermediate points in the
// collection(s). When a minor collection fails to collect
// sufficient space resizing of the young generation can occur
// an redistribute the spaces in the young generation. Mangle
// here so that unzapped regions don't get distributed to
// other spaces.
to()->mangle_unused_area();
}
swap_spaces();
assert(to()->is_empty(), "to space should be empty now");

View File

@ -170,9 +170,20 @@ bool ASPSYoungGen::resize_generation(size_t eden_size, size_t survivor_size) {
if (desired_size > orig_size) {
// Grow the generation
size_t change = desired_size - orig_size;
HeapWord* prev_low = (HeapWord*) virtual_space()->low();
if (!virtual_space()->expand_by(change)) {
return false;
}
if (ZapUnusedHeapArea) {
// Mangle newly committed space immediately because it
// can be done here more simply that after the new
// spaces have been computed.
HeapWord* new_low = (HeapWord*) virtual_space()->low();
assert(new_low < prev_low, "Did not grow");
MemRegion mangle_region(new_low, prev_low);
SpaceMangler::mangle_region(mangle_region);
}
size_changed = true;
} else if (desired_size < orig_size) {
size_t desired_change = orig_size - desired_size;
@ -215,8 +226,10 @@ bool ASPSYoungGen::resize_generation(size_t eden_size, size_t survivor_size) {
// current implementation does not allow holes between the spaces
// _young_generation_boundary has to be reset because it changes.
// so additional verification
void ASPSYoungGen::resize_spaces(size_t requested_eden_size,
size_t requested_survivor_size) {
assert(UseAdaptiveSizePolicy, "sanity check");
assert(requested_eden_size > 0 && requested_survivor_size > 0,
"just checking");
@ -276,22 +289,42 @@ void ASPSYoungGen::resize_spaces(size_t requested_eden_size,
ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
const size_t alignment = heap->intra_heap_alignment();
const bool maintain_minimum =
(requested_eden_size + 2 * requested_survivor_size) <= min_gen_size();
bool eden_from_to_order = from_start < to_start;
// Check whether from space is below to space
if (from_start < to_start) {
if (eden_from_to_order) {
// Eden, from, to
if (PrintAdaptiveSizePolicy && Verbose) {
gclog_or_tty->print_cr(" Eden, from, to:");
}
// Set eden
// Compute how big eden can be, then adjust end.
// See comment in PSYoungGen::resize_spaces() on
// calculating eden_end.
const size_t eden_size = MIN2(requested_eden_size,
pointer_delta(from_start,
// "requested_eden_size" is a goal for the size of eden
// and may not be attainable. "eden_size" below is
// calculated based on the location of from-space and
// the goal for the size of eden. from-space is
// fixed in place because it contains live data.
// The calculation is done this way to avoid 32bit
// overflow (i.e., eden_start + requested_eden_size
// may too large for representation in 32bits).
size_t eden_size;
if (maintain_minimum) {
// Only make eden larger than the requested size if
// the minimum size of the generation has to be maintained.
// This could be done in general but policy at a higher
// level is determining a requested size for eden and that
// should be honored unless there is a fundamental reason.
eden_size = pointer_delta(from_start,
eden_start,
sizeof(char)));
sizeof(char));
} else {
eden_size = MIN2(requested_eden_size,
pointer_delta(from_start, eden_start, sizeof(char)));
}
eden_end = eden_start + eden_size;
assert(eden_end >= eden_start, "addition overflowed")
@ -371,12 +404,14 @@ void ASPSYoungGen::resize_spaces(size_t requested_eden_size,
to_start = MAX2(to_start, eden_start + alignment);
// Compute how big eden can be, then adjust end.
// See comment in PSYoungGen::resize_spaces() on
// calculating eden_end.
const size_t eden_size = MIN2(requested_eden_size,
pointer_delta(to_start,
eden_start,
sizeof(char)));
// See comments above on calculating eden_end.
size_t eden_size;
if (maintain_minimum) {
eden_size = pointer_delta(to_start, eden_start, sizeof(char));
} else {
eden_size = MIN2(requested_eden_size,
pointer_delta(to_start, eden_start, sizeof(char)));
}
eden_end = eden_start + eden_size;
assert(eden_end >= eden_start, "addition overflowed")
@ -423,9 +458,47 @@ void ASPSYoungGen::resize_spaces(size_t requested_eden_size,
size_t old_from = from_space()->capacity_in_bytes();
size_t old_to = to_space()->capacity_in_bytes();
eden_space()->initialize(edenMR, true);
to_space()->initialize(toMR , true);
from_space()->initialize(fromMR, false); // Note, not cleared!
if (ZapUnusedHeapArea) {
// NUMA is a special case because a numa space is not mangled
// in order to not prematurely bind its address to memory to
// the wrong memory (i.e., don't want the GC thread to first
// touch the memory). The survivor spaces are not numa
// spaces and are mangled.
if (UseNUMA) {
if (eden_from_to_order) {
mangle_survivors(from_space(), fromMR, to_space(), toMR);
} else {
mangle_survivors(to_space(), toMR, from_space(), fromMR);
}
}
// If not mangling the spaces, do some checking to verify that
// the spaces are already mangled.
// The spaces should be correctly mangled at this point so
// do some checking here. Note that they are not being mangled
// in the calls to initialize().
// Must check mangling before the spaces are reshaped. Otherwise,
// the bottom or end of one space may have moved into an area
// covered by another space and a failure of the check may
// not correctly indicate which space is not properly mangled.
HeapWord* limit = (HeapWord*) virtual_space()->high();
eden_space()->check_mangled_unused_area(limit);
from_space()->check_mangled_unused_area(limit);
to_space()->check_mangled_unused_area(limit);
}
// When an existing space is being initialized, it is not
// mangled because the space has been previously mangled.
eden_space()->initialize(edenMR,
SpaceDecorator::Clear,
SpaceDecorator::DontMangle);
to_space()->initialize(toMR,
SpaceDecorator::Clear,
SpaceDecorator::DontMangle);
from_space()->initialize(fromMR,
SpaceDecorator::DontClear,
SpaceDecorator::DontMangle);
PSScavenge::set_young_generation_boundary(eden_space()->bottom());
assert(from_space()->top() == old_from_top, "from top changed!");
@ -446,7 +519,6 @@ void ASPSYoungGen::resize_spaces(size_t requested_eden_size,
}
space_invariants();
}
void ASPSYoungGen::reset_after_change() {
assert_locked_or_safepoint(Heap_lock);
@ -458,7 +530,9 @@ void ASPSYoungGen::reset_after_change() {
HeapWord* eden_bottom = eden_space()->bottom();
if (new_eden_bottom != eden_bottom) {
MemRegion eden_mr(new_eden_bottom, eden_space()->end());
eden_space()->initialize(eden_mr, true);
eden_space()->initialize(eden_mr,
SpaceDecorator::Clear,
SpaceDecorator::Mangle);
PSScavenge::set_young_generation_boundary(eden_space()->bottom());
}
MemRegion cmr((HeapWord*)virtual_space()->low(),

View File

@ -666,9 +666,9 @@ void CardTableExtension::resize_commit_uncommit(int changed_region,
HeapWord* new_end_for_commit =
MIN2(cur_committed.end(), _guard_region.start());
if(new_start_aligned < new_end_for_commit) {
MemRegion new_committed =
MemRegion(new_start_aligned, new_end_for_commit);
if(!new_committed.is_empty()) {
if (!os::commit_memory((char*)new_committed.start(),
new_committed.byte_size())) {
vm_exit_out_of_memory(new_committed.byte_size(),

View File

@ -938,3 +938,23 @@ void ParallelScavengeHeap::resize_old_gen(size_t desired_free_space) {
// Delegate the resize to the generation.
_old_gen->resize(desired_free_space);
}
#ifndef PRODUCT
void ParallelScavengeHeap::record_gen_tops_before_GC() {
if (ZapUnusedHeapArea) {
young_gen()->record_spaces_top();
old_gen()->record_spaces_top();
perm_gen()->record_spaces_top();
}
}
void ParallelScavengeHeap::gen_mangle_unused_area() {
if (ZapUnusedHeapArea) {
young_gen()->eden_space()->mangle_unused_area();
young_gen()->to_space()->mangle_unused_area();
young_gen()->from_space()->mangle_unused_area();
old_gen()->object_space()->mangle_unused_area();
perm_gen()->object_space()->mangle_unused_area();
}
}
#endif

View File

@ -213,6 +213,12 @@ class ParallelScavengeHeap : public CollectedHeap {
// Resize the old generation. The reserved space for the
// generation may be expanded in preparation for the resize.
void resize_old_gen(size_t desired_free_space);
// Save the tops of the spaces in all generations
void record_gen_tops_before_GC() PRODUCT_RETURN;
// Mangle the unused parts of all spaces in the heap
void gen_mangle_unused_area() PRODUCT_RETURN;
};
inline size_t ParallelScavengeHeap::set_alignment(size_t& var, size_t val)

View File

@ -98,6 +98,9 @@ void PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) {
// Increment the invocation count
heap->increment_total_collections(true /* full */);
// Save information needed to minimize mangling
heap->record_gen_tops_before_GC();
// We need to track unique mark sweep invocations as well.
_total_invocations++;
@ -188,6 +191,12 @@ void PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) {
deallocate_stacks();
if (ZapUnusedHeapArea) {
// Do a complete mangle (top to end) because the usage for
// scratch does not maintain a top pointer.
young_gen->to_space()->mangle_unused_area_complete();
}
eden_empty = young_gen->eden_space()->is_empty();
if (!eden_empty) {
eden_empty = absorb_live_data_from_eden(size_policy, young_gen, old_gen);
@ -344,6 +353,11 @@ void PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) {
perm_gen->verify_object_start_array();
}
if (ZapUnusedHeapArea) {
old_gen->object_space()->check_mangled_unused_area_complete();
perm_gen->object_space()->check_mangled_unused_area_complete();
}
NOT_PRODUCT(ref_processor()->verify_no_references_recorded());
if (PrintHeapAtGC) {

View File

@ -438,5 +438,7 @@ void PSMarkSweepDecorator::compact(bool mangle_free_space ) {
"should point inside space");
space()->set_top(compaction_top());
if (mangle_free_space) space()->mangle_unused_area();
if (mangle_free_space) {
space()->mangle_unused_area();
}
}

View File

@ -87,6 +87,15 @@ void PSOldGen::initialize_work(const char* perf_data_name, int level) {
MemRegion cmr((HeapWord*)virtual_space()->low(),
(HeapWord*)virtual_space()->high());
if (ZapUnusedHeapArea) {
// Mangle newly committed space immediately rather than
// waiting for the initialization of the space even though
// mangling is related to spaces. Doing it here eliminates
// the need to carry along information that a complete mangling
// (bottom to end) needs to be done.
SpaceMangler::mangle_region(cmr);
}
Universe::heap()->barrier_set()->resize_covered_region(cmr);
CardTableModRefBS* _ct = (CardTableModRefBS*)Universe::heap()->barrier_set();
@ -112,7 +121,9 @@ void PSOldGen::initialize_work(const char* perf_data_name, int level) {
if (_object_space == NULL)
vm_exit_during_initialization("Could not allocate an old gen space");
object_space()->initialize(cmr, true);
object_space()->initialize(cmr,
SpaceDecorator::Clear,
SpaceDecorator::Mangle);
_object_mark_sweep = new PSMarkSweepDecorator(_object_space, start_array(), MarkSweepDeadRatio);
@ -232,6 +243,19 @@ bool PSOldGen::expand_by(size_t bytes) {
assert_locked_or_safepoint(Heap_lock);
bool result = virtual_space()->expand_by(bytes);
if (result) {
if (ZapUnusedHeapArea) {
// We need to mangle the newly expanded area. The memregion spans
// end -> new_end, we assume that top -> end is already mangled.
// Do the mangling before post_resize() is called because
// the space is available for allocation after post_resize();
HeapWord* const virtual_space_high = (HeapWord*) virtual_space()->high();
assert(object_space()->end() < virtual_space_high,
"Should be true before post_resize()");
MemRegion mangle_region(object_space()->end(), virtual_space_high);
// Note that the object space has not yet been updated to
// coincede with the new underlying virtual space.
SpaceMangler::mangle_region(mangle_region);
}
post_resize();
if (UsePerfData) {
_space_counters->update_capacity();
@ -348,16 +372,7 @@ void PSOldGen::post_resize() {
start_array()->set_covered_region(new_memregion);
Universe::heap()->barrier_set()->resize_covered_region(new_memregion);
// Did we expand?
HeapWord* const virtual_space_high = (HeapWord*) virtual_space()->high();
if (object_space()->end() < virtual_space_high) {
// We need to mangle the newly expanded area. The memregion spans
// end -> new_end, we assume that top -> end is already mangled.
// This cannot be safely tested for, as allocation may be taking
// place.
MemRegion mangle_region(object_space()->end(), virtual_space_high);
object_space()->mangle_region(mangle_region);
}
// ALWAYS do this last!!
object_space()->set_end(virtual_space_high);
@ -462,3 +477,10 @@ void PSOldGen::verify_object_start_array() {
VerifyObjectStartArrayClosure check( this, &_start_array );
object_iterate(&check);
}
#ifndef PRODUCT
void PSOldGen::record_spaces_top() {
assert(ZapUnusedHeapArea, "Not mangling unused space");
object_space()->set_top_for_allocations();
}
#endif

View File

@ -185,4 +185,8 @@ class PSOldGen : public CHeapObj {
// Printing support
virtual const char* name() const { return _name; }
// Debugging support
// Save the tops of all spaces for later use during mangling.
void record_spaces_top() PRODUCT_RETURN;
};

View File

@ -200,8 +200,8 @@ void PSParallelCompact::print_chunk_ranges()
for (unsigned int id = 0; id < last_space_id; ++id) {
const MutableSpace* space = _space_info[id].space();
tty->print_cr("%u %s "
SIZE_FORMAT_W("10") " " SIZE_FORMAT_W("10") " "
SIZE_FORMAT_W("10") " " SIZE_FORMAT_W("10") " ",
SIZE_FORMAT_W(10) " " SIZE_FORMAT_W(10) " "
SIZE_FORMAT_W(10) " " SIZE_FORMAT_W(10) " ",
id, space_names[id],
summary_data().addr_to_chunk_idx(space->bottom()),
summary_data().addr_to_chunk_idx(space->top()),
@ -213,8 +213,8 @@ void PSParallelCompact::print_chunk_ranges()
void
print_generic_summary_chunk(size_t i, const ParallelCompactData::ChunkData* c)
{
#define CHUNK_IDX_FORMAT SIZE_FORMAT_W("7")
#define CHUNK_DATA_FORMAT SIZE_FORMAT_W("5")
#define CHUNK_IDX_FORMAT SIZE_FORMAT_W(7)
#define CHUNK_DATA_FORMAT SIZE_FORMAT_W(5)
ParallelCompactData& sd = PSParallelCompact::summary_data();
size_t dci = c->destination() ? sd.addr_to_chunk_idx(c->destination()) : 0;
@ -269,9 +269,9 @@ print_initial_summary_chunk(size_t i,
const ParallelCompactData::ChunkData* c,
bool newline = true)
{
tty->print(SIZE_FORMAT_W("5") " " PTR_FORMAT " "
SIZE_FORMAT_W("5") " " SIZE_FORMAT_W("5") " "
SIZE_FORMAT_W("5") " " SIZE_FORMAT_W("5") " %d",
tty->print(SIZE_FORMAT_W(5) " " PTR_FORMAT " "
SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " "
SIZE_FORMAT_W(5) " " SIZE_FORMAT_W(5) " %d",
i, c->destination(),
c->partial_obj_size(), c->live_obj_size(),
c->data_size(), c->source_chunk(), c->destination_count());
@ -326,7 +326,7 @@ print_initial_summary_data(ParallelCompactData& summary_data,
}
print_initial_summary_chunk(i, c, false);
tty->print_cr(" %12.10f " SIZE_FORMAT_W("10") " " SIZE_FORMAT_W("10"),
tty->print_cr(" %12.10f " SIZE_FORMAT_W(10) " " SIZE_FORMAT_W(10),
reclaimed_ratio, dead_to_right, live_to_right);
live_to_right -= c->data_size();
@ -338,8 +338,8 @@ print_initial_summary_data(ParallelCompactData& summary_data,
print_initial_summary_chunk(i, summary_data.chunk(i));
}
tty->print_cr("max: " SIZE_FORMAT_W("4") " d2r=" SIZE_FORMAT_W("10") " "
"l2r=" SIZE_FORMAT_W("10") " max_ratio=%14.12f",
tty->print_cr("max: " SIZE_FORMAT_W(4) " d2r=" SIZE_FORMAT_W(10) " "
"l2r=" SIZE_FORMAT_W(10) " max_ratio=%14.12f",
max_reclaimed_ratio_chunk, max_dead_to_right,
max_live_to_right, max_reclaimed_ratio);
}
@ -1060,6 +1060,10 @@ void PSParallelCompact::post_compact()
ref_processor()->enqueue_discovered_references(NULL);
if (ZapUnusedHeapArea) {
heap->gen_mangle_unused_area();
}
// Update time of last GC
reset_millis_since_last_gc();
}
@ -1119,8 +1123,8 @@ PSParallelCompact::compute_dense_prefix_via_density(const SpaceId id,
HeapWord* chunk_destination = cp->destination();
const size_t cur_deadwood = pointer_delta(dense_prefix, chunk_destination);
if (TraceParallelOldGCDensePrefix && Verbose) {
tty->print_cr("c#=" SIZE_FORMAT_W("04") " dst=" PTR_FORMAT " "
"dp=" SIZE_FORMAT_W("08") " " "cdw=" SIZE_FORMAT_W("08"),
tty->print_cr("c#=" SIZE_FORMAT_W(4) " dst=" PTR_FORMAT " "
"dp=" SIZE_FORMAT_W(8) " " "cdw=" SIZE_FORMAT_W(8),
sd.chunk(cp), chunk_destination,
dense_prefix, cur_deadwood);
}
@ -1145,7 +1149,7 @@ PSParallelCompact::compute_dense_prefix_via_density(const SpaceId id,
return dense_prefix;
}
if (TraceParallelOldGCDensePrefix && Verbose) {
tty->print_cr("backing up from c=" SIZE_FORMAT_W("4") " d2r=%10.8f "
tty->print_cr("backing up from c=" SIZE_FORMAT_W(4) " d2r=%10.8f "
"pc_d2r=%10.8f", sd.chunk(cp), density_to_right,
prev_chunk_density_to_right);
}
@ -1182,7 +1186,7 @@ void PSParallelCompact::print_dense_prefix_stats(const char* const algorithm,
const size_t live_to_right = new_top - cp->destination();
const size_t dead_to_right = space->top() - addr - live_to_right;
tty->print_cr("%s=" PTR_FORMAT " dpc=" SIZE_FORMAT_W("05") " "
tty->print_cr("%s=" PTR_FORMAT " dpc=" SIZE_FORMAT_W(5) " "
"spl=" SIZE_FORMAT " "
"d2l=" SIZE_FORMAT " d2l%%=%6.4f "
"d2r=" SIZE_FORMAT " l2r=" SIZE_FORMAT
@ -1522,26 +1526,28 @@ void
PSParallelCompact::summarize_space(SpaceId id, bool maximum_compaction)
{
assert(id < last_space_id, "id out of range");
assert(_space_info[id].dense_prefix() == _space_info[id].space()->bottom(),
"should have been set in summarize_spaces_quick()");
const MutableSpace* space = _space_info[id].space();
HeapWord** new_top_addr = _space_info[id].new_top_addr();
if (_space_info[id].new_top() != space->bottom()) {
HeapWord* dense_prefix_end = compute_dense_prefix(id, maximum_compaction);
_space_info[id].set_dense_prefix(dense_prefix_end);
#ifndef PRODUCT
if (TraceParallelOldGCDensePrefix) {
print_dense_prefix_stats("ratio", id, maximum_compaction, dense_prefix_end);
print_dense_prefix_stats("ratio", id, maximum_compaction,
dense_prefix_end);
HeapWord* addr = compute_dense_prefix_via_density(id, maximum_compaction);
print_dense_prefix_stats("density", id, maximum_compaction, addr);
}
#endif // #ifndef PRODUCT
// If dead space crosses the dense prefix boundary, it is (at least partially)
// filled with a dummy object, marked live and added to the summary data.
// This simplifies the copy/update phase and must be done before the final
// locations of objects are determined, to prevent leaving a fragment of dead
// space that is too small to fill with an object.
// If dead space crosses the dense prefix boundary, it is (at least
// partially) filled with a dummy object, marked live and added to the
// summary data. This simplifies the copy/update phase and must be done
// before the final locations of objects are determined, to prevent leaving
// a fragment of dead space that is too small to fill with an object.
if (!maximum_compaction && dense_prefix_end != space->bottom()) {
fill_dense_prefix_end(id);
}
@ -1550,20 +1556,23 @@ PSParallelCompact::summarize_space(SpaceId id, bool maximum_compaction)
_summary_data.summarize_dense_prefix(space->bottom(), dense_prefix_end);
_summary_data.summarize(dense_prefix_end, space->end(),
dense_prefix_end, space->top(),
new_top_addr);
_space_info[id].new_top_addr());
}
if (TraceParallelOldGCSummaryPhase) {
const size_t chunk_size = ParallelCompactData::ChunkSize;
HeapWord* const dense_prefix_end = _space_info[id].dense_prefix();
const size_t dp_chunk = _summary_data.addr_to_chunk_idx(dense_prefix_end);
const size_t dp_words = pointer_delta(dense_prefix_end, space->bottom());
const HeapWord* nt_aligned_up = _summary_data.chunk_align_up(*new_top_addr);
HeapWord* const new_top = _space_info[id].new_top();
const HeapWord* nt_aligned_up = _summary_data.chunk_align_up(new_top);
const size_t cr_words = pointer_delta(nt_aligned_up, dense_prefix_end);
tty->print_cr("id=%d cap=" SIZE_FORMAT " dp=" PTR_FORMAT " "
"dp_chunk=" SIZE_FORMAT " " "dp_count=" SIZE_FORMAT " "
"cr_count=" SIZE_FORMAT " " "nt=" PTR_FORMAT,
id, space->capacity_in_words(), dense_prefix_end,
dp_chunk, dp_words / chunk_size,
cr_words / chunk_size, *new_top_addr);
cr_words / chunk_size, new_top);
}
}
@ -1632,7 +1641,7 @@ void PSParallelCompact::summary_phase(ParCompactionManager* cm,
const size_t live = pointer_delta(_space_info[id].new_top(),
space->bottom());
const size_t available = pointer_delta(target_space_end, *new_top_addr);
if (live <= available) {
if (live > 0 && live <= available) {
// All the live data will fit.
if (TraceParallelOldGCSummaryPhase) {
tty->print_cr("summarizing %d into old_space @ " PTR_FORMAT,
@ -1642,16 +1651,18 @@ void PSParallelCompact::summary_phase(ParCompactionManager* cm,
space->bottom(), space->top(),
new_top_addr);
// Reset the new_top value for the space.
_space_info[id].set_new_top(space->bottom());
// Clear the source_chunk field for each chunk in the space.
HeapWord* const new_top = _space_info[id].new_top();
HeapWord* const clear_end = _summary_data.chunk_align_up(new_top);
ChunkData* beg_chunk = _summary_data.addr_to_chunk_ptr(space->bottom());
ChunkData* end_chunk = _summary_data.addr_to_chunk_ptr(space->top() - 1);
while (beg_chunk <= end_chunk) {
ChunkData* end_chunk = _summary_data.addr_to_chunk_ptr(clear_end);
while (beg_chunk < end_chunk) {
beg_chunk->set_source_chunk(0);
++beg_chunk;
}
// Reset the new_top value for the space.
_space_info[id].set_new_top(space->bottom());
}
}
@ -1961,6 +1972,11 @@ void PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
PSPermGen* perm_gen = heap->perm_gen();
PSAdaptiveSizePolicy* size_policy = heap->size_policy();
if (ZapUnusedHeapArea) {
// Save information needed to minimize mangling
heap->record_gen_tops_before_GC();
}
_print_phases = PrintGCDetails && PrintParallelOldGCPhaseTimes;
// Make sure data structures are sane, make the heap parsable, and do other
@ -2129,7 +2145,8 @@ void PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
size_t max_eden_size = young_gen->max_size() -
young_gen->from_space()->capacity_in_bytes() -
young_gen->to_space()->capacity_in_bytes();
size_policy->compute_generation_free_space(young_gen->used_in_bytes(),
size_policy->compute_generation_free_space(
young_gen->used_in_bytes(),
young_gen->eden_space()->used_in_bytes(),
old_gen->used_in_bytes(),
perm_gen->used_in_bytes(),
@ -2139,7 +2156,8 @@ void PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
true /* full gc*/,
gc_cause);
heap->resize_old_gen(size_policy->calculated_old_free_size_in_bytes());
heap->resize_old_gen(
size_policy->calculated_old_free_size_in_bytes());
// Don't resize the young generation at an major collection. A
// desired young generation size may have been calculated but
@ -2212,6 +2230,11 @@ void PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
perm_gen->verify_object_start_array();
}
if (ZapUnusedHeapArea) {
old_gen->object_space()->check_mangled_unused_area_complete();
perm_gen->object_space()->check_mangled_unused_area_complete();
}
NOT_PRODUCT(ref_processor()->verify_no_references_recorded());
collection_exit.update();
@ -2499,7 +2522,7 @@ void PSParallelCompact::enqueue_chunk_draining_tasks(GCTaskQueue* q,
if (TraceParallelOldGCCompactionPhase && Verbose) {
const size_t count_mod_8 = fillable_chunks & 7;
if (count_mod_8 == 0) gclog_or_tty->print("fillable: ");
gclog_or_tty->print(" " SIZE_FORMAT_W("7"), cur);
gclog_or_tty->print(" " SIZE_FORMAT_W(7), cur);
if (count_mod_8 == 7) gclog_or_tty->cr();
}

View File

@ -716,6 +716,99 @@ class BitBlockUpdateClosure: public ParMarkBitMapClosure {
virtual IterationStatus do_addr(HeapWord* addr, size_t words);
};
// The UseParallelOldGC collector is a stop-the-world garbage
// collector that does parts of the collection using parallel threads.
// The collection includes the tenured generation and the young
// generation. The permanent generation is collected at the same
// time as the other two generations but the permanent generation
// is collect by a single GC thread. The permanent generation is
// collected serially because of the requirement that during the
// processing of a klass AAA, any objects reference by AAA must
// already have been processed. This requirement is enforced by
// a left (lower address) to right (higher address) sliding compaction.
//
// There are four phases of the collection.
//
// - marking phase
// - summary phase
// - compacting phase
// - clean up phase
//
// Roughly speaking these phases correspond, respectively, to
// - mark all the live objects
// - calculate the destination of each object at the end of the collection
// - move the objects to their destination
// - update some references and reinitialize some variables
//
// These three phases are invoked in PSParallelCompact::invoke_no_policy().
// The marking phase is implemented in PSParallelCompact::marking_phase()
// and does a complete marking of the heap.
// The summary phase is implemented in PSParallelCompact::summary_phase().
// The move and update phase is implemented in PSParallelCompact::compact().
//
// A space that is being collected is divided into chunks and with
// each chunk is associated an object of type ParallelCompactData.
// Each chunk is of a fixed size and typically will contain more than
// 1 object and may have parts of objects at the front and back of the
// chunk.
//
// chunk -----+---------------------+----------
// objects covered [ AAA )[ BBB )[ CCC )[ DDD )
//
// The marking phase does a complete marking of all live objects in the
// heap. The marking also compiles the size of the data for
// all live objects covered by the chunk. This size includes the
// part of any live object spanning onto the chunk (part of AAA
// if it is live) from the front, all live objects contained in the chunk
// (BBB and/or CCC if they are live), and the part of any live objects
// covered by the chunk that extends off the chunk (part of DDD if it is
// live). The marking phase uses multiple GC threads and marking is
// done in a bit array of type ParMarkBitMap. The marking of the
// bit map is done atomically as is the accumulation of the size of the
// live objects covered by a chunk.
//
// The summary phase calculates the total live data to the left of
// each chunk XXX. Based on that total and the bottom of the space,
// it can calculate the starting location of the live data in XXX.
// The summary phase calculates for each chunk XXX quantites such as
//
// - the amount of live data at the beginning of a chunk from an object
// entering the chunk.
// - the location of the first live data on the chunk
// - a count of the number of chunks receiving live data from XXX.
//
// See ParallelCompactData for precise details. The summary phase also
// calculates the dense prefix for the compaction. The dense prefix
// is a portion at the beginning of the space that is not moved. The
// objects in the dense prefix do need to have their object references
// updated. See method summarize_dense_prefix().
//
// The summary phase is done using 1 GC thread.
//
// The compaction phase moves objects to their new location and updates
// all references in the object.
//
// A current exception is that objects that cross a chunk boundary
// are moved but do not have their references updated. References are
// not updated because it cannot easily be determined if the klass
// pointer KKK for the object AAA has been updated. KKK likely resides
// in a chunk to the left of the chunk containing AAA. These AAA's
// have there references updated at the end in a clean up phase.
// See the method PSParallelCompact::update_deferred_objects(). An
// alternate strategy is being investigated for this deferral of updating.
//
// Compaction is done on a chunk basis. A chunk that is ready to be
// filled is put on a ready list and GC threads take chunk off the list
// and fill them. A chunk is ready to be filled if it
// empty of live objects. Such a chunk may have been initially
// empty (only contained
// dead objects) or may have had all its live objects copied out already.
// A chunk that compacts into itself is also ready for filling. The
// ready list is initially filled with empty chunks and chunks compacting
// into themselves. There is always at least 1 chunk that can be put on
// the ready list. The chunks are atomically added and removed from
// the ready list.
//
class PSParallelCompact : AllStatic {
public:
// Convenient access to type names.

View File

@ -265,6 +265,11 @@ bool PSScavenge::invoke_no_policy() {
young_gen->eden_space()->accumulate_statistics();
}
if (ZapUnusedHeapArea) {
// Save information needed to minimize mangling
heap->record_gen_tops_before_GC();
}
if (PrintHeapAtGC) {
Universe::print_heap_before_gc();
}
@ -315,7 +320,7 @@ bool PSScavenge::invoke_no_policy() {
if (!ScavengeWithObjectsInToSpace) {
assert(young_gen->to_space()->is_empty(),
"Attempt to scavenge with live objects in to_space");
young_gen->to_space()->clear();
young_gen->to_space()->clear(SpaceDecorator::Mangle);
} else if (ZapUnusedHeapArea) {
young_gen->to_space()->mangle_unused_area();
}
@ -437,8 +442,10 @@ bool PSScavenge::invoke_no_policy() {
if (!promotion_failure_occurred) {
// Swap the survivor spaces.
young_gen->eden_space()->clear();
young_gen->from_space()->clear();
young_gen->eden_space()->clear(SpaceDecorator::Mangle);
young_gen->from_space()->clear(SpaceDecorator::Mangle);
young_gen->swap_spaces();
size_t survived = young_gen->from_space()->used_in_bytes();
@ -600,6 +607,12 @@ bool PSScavenge::invoke_no_policy() {
Universe::print_heap_after_gc();
}
if (ZapUnusedHeapArea) {
young_gen->eden_space()->check_mangled_unused_area_complete();
young_gen->from_space()->check_mangled_unused_area_complete();
young_gen->to_space()->check_mangled_unused_area_complete();
}
scavenge_exit.update();
if (PrintGCTaskTimeStamps) {

View File

@ -36,7 +36,7 @@ PSYoungGen::PSYoungGen(size_t initial_size,
void PSYoungGen::initialize_virtual_space(ReservedSpace rs, size_t alignment) {
assert(_init_gen_size != 0, "Should have a finite size");
_virtual_space = new PSVirtualSpace(rs, alignment);
if (!_virtual_space->expand_by(_init_gen_size)) {
if (!virtual_space()->expand_by(_init_gen_size)) {
vm_exit_during_initialization("Could not reserve enough space for "
"object heap");
}
@ -49,13 +49,20 @@ void PSYoungGen::initialize(ReservedSpace rs, size_t alignment) {
void PSYoungGen::initialize_work() {
_reserved = MemRegion((HeapWord*)_virtual_space->low_boundary(),
(HeapWord*)_virtual_space->high_boundary());
_reserved = MemRegion((HeapWord*)virtual_space()->low_boundary(),
(HeapWord*)virtual_space()->high_boundary());
MemRegion cmr((HeapWord*)_virtual_space->low(),
(HeapWord*)_virtual_space->high());
MemRegion cmr((HeapWord*)virtual_space()->low(),
(HeapWord*)virtual_space()->high());
Universe::heap()->barrier_set()->resize_covered_region(cmr);
if (ZapUnusedHeapArea) {
// Mangle newly committed space immediately because it
// can be done here more simply that after the new
// spaces have been computed.
SpaceMangler::mangle_region(cmr);
}
if (UseNUMA) {
_eden_space = new MutableNUMASpace();
} else {
@ -89,7 +96,7 @@ void PSYoungGen::initialize_work() {
// Compute maximum space sizes for performance counters
ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
size_t alignment = heap->intra_heap_alignment();
size_t size = _virtual_space->reserved_size();
size_t size = virtual_space()->reserved_size();
size_t max_survivor_size;
size_t max_eden_size;
@ -142,7 +149,7 @@ void PSYoungGen::compute_initial_space_boundaries() {
// Compute sizes
size_t alignment = heap->intra_heap_alignment();
size_t size = _virtual_space->committed_size();
size_t size = virtual_space()->committed_size();
size_t survivor_size = size / InitialSurvivorRatio;
survivor_size = align_size_down(survivor_size, alignment);
@ -164,18 +171,18 @@ void PSYoungGen::compute_initial_space_boundaries() {
}
void PSYoungGen::set_space_boundaries(size_t eden_size, size_t survivor_size) {
assert(eden_size < _virtual_space->committed_size(), "just checking");
assert(eden_size < virtual_space()->committed_size(), "just checking");
assert(eden_size > 0 && survivor_size > 0, "just checking");
// Initial layout is Eden, to, from. After swapping survivor spaces,
// that leaves us with Eden, from, to, which is step one in our two
// step resize-with-live-data procedure.
char *eden_start = _virtual_space->low();
char *eden_start = virtual_space()->low();
char *to_start = eden_start + eden_size;
char *from_start = to_start + survivor_size;
char *from_end = from_start + survivor_size;
assert(from_end == _virtual_space->high(), "just checking");
assert(from_end == virtual_space()->high(), "just checking");
assert(is_object_aligned((intptr_t)eden_start), "checking alignment");
assert(is_object_aligned((intptr_t)to_start), "checking alignment");
assert(is_object_aligned((intptr_t)from_start), "checking alignment");
@ -184,9 +191,9 @@ void PSYoungGen::set_space_boundaries(size_t eden_size, size_t survivor_size) {
MemRegion to_mr ((HeapWord*)to_start, (HeapWord*)from_start);
MemRegion from_mr((HeapWord*)from_start, (HeapWord*)from_end);
eden_space()->initialize(eden_mr, true);
to_space()->initialize(to_mr , true);
from_space()->initialize(from_mr, true);
eden_space()->initialize(eden_mr, true, ZapUnusedHeapArea);
to_space()->initialize(to_mr , true, ZapUnusedHeapArea);
from_space()->initialize(from_mr, true, ZapUnusedHeapArea);
}
#ifndef PRODUCT
@ -207,7 +214,7 @@ void PSYoungGen::space_invariants() {
char* to_start = (char*)to_space()->bottom();
char* to_end = (char*)to_space()->end();
guarantee(eden_start >= _virtual_space->low(), "eden bottom");
guarantee(eden_start >= virtual_space()->low(), "eden bottom");
guarantee(eden_start < eden_end, "eden space consistency");
guarantee(from_start < from_end, "from space consistency");
guarantee(to_start < to_end, "to space consistency");
@ -217,29 +224,29 @@ void PSYoungGen::space_invariants() {
// Eden, from, to
guarantee(eden_end <= from_start, "eden/from boundary");
guarantee(from_end <= to_start, "from/to boundary");
guarantee(to_end <= _virtual_space->high(), "to end");
guarantee(to_end <= virtual_space()->high(), "to end");
} else {
// Eden, to, from
guarantee(eden_end <= to_start, "eden/to boundary");
guarantee(to_end <= from_start, "to/from boundary");
guarantee(from_end <= _virtual_space->high(), "from end");
guarantee(from_end <= virtual_space()->high(), "from end");
}
// More checks that the virtual space is consistent with the spaces
assert(_virtual_space->committed_size() >=
assert(virtual_space()->committed_size() >=
(eden_space()->capacity_in_bytes() +
to_space()->capacity_in_bytes() +
from_space()->capacity_in_bytes()), "Committed size is inconsistent");
assert(_virtual_space->committed_size() <= _virtual_space->reserved_size(),
assert(virtual_space()->committed_size() <= virtual_space()->reserved_size(),
"Space invariant");
char* eden_top = (char*)eden_space()->top();
char* from_top = (char*)from_space()->top();
char* to_top = (char*)to_space()->top();
assert(eden_top <= _virtual_space->high(), "eden top");
assert(from_top <= _virtual_space->high(), "from top");
assert(to_top <= _virtual_space->high(), "to top");
assert(eden_top <= virtual_space()->high(), "eden top");
assert(from_top <= virtual_space()->high(), "from top");
assert(to_top <= virtual_space()->high(), "to top");
_virtual_space->verify();
virtual_space()->verify();
}
#endif
@ -265,8 +272,8 @@ void PSYoungGen::resize(size_t eden_size, size_t survivor_size) {
bool PSYoungGen::resize_generation(size_t eden_size, size_t survivor_size) {
const size_t alignment = _virtual_space->alignment();
size_t orig_size = _virtual_space->committed_size();
const size_t alignment = virtual_space()->alignment();
size_t orig_size = virtual_space()->committed_size();
bool size_changed = false;
// There used to be this guarantee there.
@ -288,10 +295,18 @@ bool PSYoungGen::resize_generation(size_t eden_size, size_t survivor_size) {
// Grow the generation
size_t change = desired_size - orig_size;
assert(change % alignment == 0, "just checking");
if (!_virtual_space->expand_by(change)) {
HeapWord* prev_high = (HeapWord*) virtual_space()->high();
if (!virtual_space()->expand_by(change)) {
return false; // Error if we fail to resize!
}
if (ZapUnusedHeapArea) {
// Mangle newly committed space immediately because it
// can be done here more simply that after the new
// spaces have been computed.
HeapWord* new_high = (HeapWord*) virtual_space()->high();
MemRegion mangle_region(prev_high, new_high);
SpaceMangler::mangle_region(mangle_region);
}
size_changed = true;
} else if (desired_size < orig_size) {
size_t desired_change = orig_size - desired_size;
@ -321,19 +336,95 @@ bool PSYoungGen::resize_generation(size_t eden_size, size_t survivor_size) {
post_resize();
if (Verbose && PrintGC) {
size_t current_size = _virtual_space->committed_size();
size_t current_size = virtual_space()->committed_size();
gclog_or_tty->print_cr("PSYoung generation size changed: "
SIZE_FORMAT "K->" SIZE_FORMAT "K",
orig_size/K, current_size/K);
}
}
guarantee(eden_plus_survivors <= _virtual_space->committed_size() ||
_virtual_space->committed_size() == max_size(), "Sanity");
guarantee(eden_plus_survivors <= virtual_space()->committed_size() ||
virtual_space()->committed_size() == max_size(), "Sanity");
return true;
}
#ifndef PRODUCT
// In the numa case eden is not mangled so a survivor space
// moving into a region previously occupied by a survivor
// may find an unmangled region. Also in the PS case eden
// to-space and from-space may not touch (i.e., there may be
// gaps between them due to movement while resizing the
// spaces). Those gaps must be mangled.
void PSYoungGen::mangle_survivors(MutableSpace* s1,
MemRegion s1MR,
MutableSpace* s2,
MemRegion s2MR) {
// Check eden and gap between eden and from-space, in deciding
// what to mangle in from-space. Check the gap between from-space
// and to-space when deciding what to mangle.
//
// +--------+ +----+ +---+
// | eden | |s1 | |s2 |
// +--------+ +----+ +---+
// +-------+ +-----+
// |s1MR | |s2MR |
// +-------+ +-----+
// All of survivor-space is properly mangled so find the
// upper bound on the mangling for any portion above current s1.
HeapWord* delta_end = MIN2(s1->bottom(), s1MR.end());
MemRegion delta1_left;
if (s1MR.start() < delta_end) {
delta1_left = MemRegion(s1MR.start(), delta_end);
s1->mangle_region(delta1_left);
}
// Find any portion to the right of the current s1.
HeapWord* delta_start = MAX2(s1->end(), s1MR.start());
MemRegion delta1_right;
if (delta_start < s1MR.end()) {
delta1_right = MemRegion(delta_start, s1MR.end());
s1->mangle_region(delta1_right);
}
// Similarly for the second survivor space except that
// any of the new region that overlaps with the current
// region of the first survivor space has already been
// mangled.
delta_end = MIN2(s2->bottom(), s2MR.end());
delta_start = MAX2(s2MR.start(), s1->end());
MemRegion delta2_left;
if (s2MR.start() < delta_end) {
delta2_left = MemRegion(s2MR.start(), delta_end);
s2->mangle_region(delta2_left);
}
delta_start = MAX2(s2->end(), s2MR.start());
MemRegion delta2_right;
if (delta_start < s2MR.end()) {
s2->mangle_region(delta2_right);
}
if (TraceZapUnusedHeapArea) {
// s1
gclog_or_tty->print_cr("Current region: [" PTR_FORMAT ", " PTR_FORMAT ") "
"New region: [" PTR_FORMAT ", " PTR_FORMAT ")",
s1->bottom(), s1->end(), s1MR.start(), s1MR.end());
gclog_or_tty->print_cr(" Mangle before: [" PTR_FORMAT ", "
PTR_FORMAT ") Mangle after: [" PTR_FORMAT ", " PTR_FORMAT ")",
delta1_left.start(), delta1_left.end(), delta1_right.start(),
delta1_right.end());
// s2
gclog_or_tty->print_cr("Current region: [" PTR_FORMAT ", " PTR_FORMAT ") "
"New region: [" PTR_FORMAT ", " PTR_FORMAT ")",
s2->bottom(), s2->end(), s2MR.start(), s2MR.end());
gclog_or_tty->print_cr(" Mangle before: [" PTR_FORMAT ", "
PTR_FORMAT ") Mangle after: [" PTR_FORMAT ", " PTR_FORMAT ")",
delta2_left.start(), delta2_left.end(), delta2_right.start(),
delta2_right.end());
}
}
#endif // NOT PRODUCT
void PSYoungGen::resize_spaces(size_t requested_eden_size,
size_t requested_survivor_size) {
@ -396,9 +487,11 @@ void PSYoungGen::resize_spaces(size_t requested_eden_size,
const bool maintain_minimum =
(requested_eden_size + 2 * requested_survivor_size) <= min_gen_size();
bool eden_from_to_order = from_start < to_start;
// Check whether from space is below to space
if (from_start < to_start) {
if (eden_from_to_order) {
// Eden, from, to
eden_from_to_order = true;
if (PrintAdaptiveSizePolicy && Verbose) {
gclog_or_tty->print_cr(" Eden, from, to:");
}
@ -435,7 +528,7 @@ void PSYoungGen::resize_spaces(size_t requested_eden_size,
// extra calculations.
// First calculate an optimal to-space
to_end = (char*)_virtual_space->high();
to_end = (char*)virtual_space()->high();
to_start = (char*)pointer_delta(to_end, (char*)requested_survivor_size,
sizeof(char));
@ -491,7 +584,7 @@ void PSYoungGen::resize_spaces(size_t requested_eden_size,
// to space as if we were able to resize from space, even though from
// space is not modified.
// Giving eden priority was tried and gave poorer performance.
to_end = (char*)pointer_delta(_virtual_space->high(),
to_end = (char*)pointer_delta(virtual_space()->high(),
(char*)requested_survivor_size,
sizeof(char));
to_end = MIN2(to_end, from_start);
@ -560,9 +653,45 @@ void PSYoungGen::resize_spaces(size_t requested_eden_size,
size_t old_from = from_space()->capacity_in_bytes();
size_t old_to = to_space()->capacity_in_bytes();
eden_space()->initialize(edenMR, true);
to_space()->initialize(toMR , true);
from_space()->initialize(fromMR, false); // Note, not cleared!
if (ZapUnusedHeapArea) {
// NUMA is a special case because a numa space is not mangled
// in order to not prematurely bind its address to memory to
// the wrong memory (i.e., don't want the GC thread to first
// touch the memory). The survivor spaces are not numa
// spaces and are mangled.
if (UseNUMA) {
if (eden_from_to_order) {
mangle_survivors(from_space(), fromMR, to_space(), toMR);
} else {
mangle_survivors(to_space(), toMR, from_space(), fromMR);
}
}
// If not mangling the spaces, do some checking to verify that
// the spaces are already mangled.
// The spaces should be correctly mangled at this point so
// do some checking here. Note that they are not being mangled
// in the calls to initialize().
// Must check mangling before the spaces are reshaped. Otherwise,
// the bottom or end of one space may have moved into an area
// covered by another space and a failure of the check may
// not correctly indicate which space is not properly mangled.
HeapWord* limit = (HeapWord*) virtual_space()->high();
eden_space()->check_mangled_unused_area(limit);
from_space()->check_mangled_unused_area(limit);
to_space()->check_mangled_unused_area(limit);
}
// When an existing space is being initialized, it is not
// mangled because the space has been previously mangled.
eden_space()->initialize(edenMR,
SpaceDecorator::Clear,
SpaceDecorator::DontMangle);
to_space()->initialize(toMR,
SpaceDecorator::Clear,
SpaceDecorator::DontMangle);
from_space()->initialize(fromMR,
SpaceDecorator::DontClear,
SpaceDecorator::DontMangle);
assert(from_space()->top() == old_from_top, "from top changed!");
@ -671,7 +800,7 @@ void PSYoungGen::print_on(outputStream* st) const {
st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K",
capacity_in_bytes()/K, used_in_bytes()/K);
}
_virtual_space->print_space_boundaries_on(st);
virtual_space()->print_space_boundaries_on(st);
st->print(" eden"); eden_space()->print_on(st);
st->print(" from"); from_space()->print_on(st);
st->print(" to "); to_space()->print_on(st);
@ -774,7 +903,9 @@ void PSYoungGen::reset_survivors_after_shrink() {
// Was there a shrink of the survivor space?
if (new_end < space_shrinking->end()) {
MemRegion mr(space_shrinking->bottom(), new_end);
space_shrinking->initialize(mr, false /* clear */);
space_shrinking->initialize(mr,
SpaceDecorator::DontClear,
SpaceDecorator::Mangle);
}
}
@ -809,3 +940,12 @@ void PSYoungGen::verify(bool allow_dirty) {
from_space()->verify(allow_dirty);
to_space()->verify(allow_dirty);
}
#ifndef PRODUCT
void PSYoungGen::record_spaces_top() {
assert(ZapUnusedHeapArea, "Not mangling unused space");
eden_space()->set_top_for_allocations();
from_space()->set_top_for_allocations();
to_space()->set_top_for_allocations();
}
#endif

View File

@ -179,4 +179,12 @@ class PSYoungGen : public CHeapObj {
// Space boundary invariant checker
void space_invariants() PRODUCT_RETURN;
// Helper for mangling survivor spaces.
void mangle_survivors(MutableSpace* s1,
MemRegion s1MR,
MutableSpace* s2,
MemRegion s2MR) PRODUCT_RETURN;
void record_spaces_top() PRODUCT_RETURN;
};

View File

@ -58,6 +58,12 @@ class AdaptiveWeightedAverage : public CHeapObj {
_average(0.0), _sample_count(0), _weight(weight), _last_sample(0.0) {
}
void clear() {
_average = 0;
_sample_count = 0;
_last_sample = 0;
}
// Accessors
float average() const { return _average; }
unsigned weight() const { return _weight; }
@ -115,6 +121,12 @@ class AdaptivePaddedAverage : public AdaptiveWeightedAverage {
float deviation() const { return _deviation; }
unsigned padding() const { return _padding; }
void clear() {
AdaptiveWeightedAverage::clear();
_padded_avg = 0;
_deviation = 0;
}
// Override
void sample(float new_sample);
};

View File

@ -42,19 +42,31 @@ MutableNUMASpace::~MutableNUMASpace() {
delete lgrp_spaces();
}
#ifndef PRODUCT
void MutableNUMASpace::mangle_unused_area() {
for (int i = 0; i < lgrp_spaces()->length(); i++) {
LGRPSpace *ls = lgrp_spaces()->at(i);
MutableSpace *s = ls->space();
if (!os::numa_has_static_binding()) {
HeapWord *top = MAX2((HeapWord*)round_down((intptr_t)s->top(), page_size()), s->bottom());
if (top < s->end()) {
ls->add_invalid_region(MemRegion(top, s->end()));
// This method should do nothing.
// It can be called on a numa space during a full compaction.
}
void MutableNUMASpace::mangle_unused_area_complete() {
// This method should do nothing.
// It can be called on a numa space during a full compaction.
}
s->mangle_unused_area();
void MutableNUMASpace::mangle_region(MemRegion mr) {
// This method should do nothing because numa spaces are not mangled.
}
void MutableNUMASpace::set_top_for_allocations(HeapWord* v) {
assert(false, "Do not mangle MutableNUMASpace's");
}
void MutableNUMASpace::set_top_for_allocations() {
// This method should do nothing.
}
void MutableNUMASpace::check_mangled_unused_area(HeapWord* limit) {
// This method should do nothing.
}
void MutableNUMASpace::check_mangled_unused_area_complete() {
// This method should do nothing.
}
#endif // NOT_PRODUCT
// There may be unallocated holes in the middle chunks
// that should be filled with dead objects to ensure parseability.
@ -129,7 +141,20 @@ size_t MutableNUMASpace::free_in_words() const {
size_t MutableNUMASpace::tlab_capacity(Thread *thr) const {
guarantee(thr != NULL, "No thread");
int lgrp_id = thr->lgrp_id();
assert(lgrp_id != -1, "No lgrp_id set");
if (lgrp_id == -1) {
// This case can occur after the topology of the system has
// changed. Thread can change their location, the new home
// group will be determined during the first allocation
// attempt. For now we can safely assume that all spaces
// have equal size because the whole space will be reinitialized.
if (lgrp_spaces()->length() > 0) {
return capacity_in_bytes() / lgrp_spaces()->length();
} else {
assert(false, "There should be at least one locality group");
return 0;
}
}
// That's the normal case, where we know the locality group of the thread.
int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);
if (i == -1) {
return 0;
@ -138,9 +163,17 @@ size_t MutableNUMASpace::tlab_capacity(Thread *thr) const {
}
size_t MutableNUMASpace::unsafe_max_tlab_alloc(Thread *thr) const {
// Please see the comments for tlab_capacity().
guarantee(thr != NULL, "No thread");
int lgrp_id = thr->lgrp_id();
assert(lgrp_id != -1, "No lgrp_id set");
if (lgrp_id == -1) {
if (lgrp_spaces()->length() > 0) {
return free_in_bytes() / lgrp_spaces()->length();
} else {
assert(false, "There should be at least one locality group");
return 0;
}
}
int i = lgrp_spaces()->find(&lgrp_id, LGRPSpace::equals);
if (i == -1) {
return 0;
@ -238,12 +271,20 @@ void MutableNUMASpace::free_region(MemRegion mr) {
void MutableNUMASpace::update() {
if (update_layout(false)) {
// If the topology has changed, make all chunks zero-sized.
// And clear the alloc-rate statistics.
// In future we may want to handle this more gracefully in order
// to avoid the reallocation of the pages as much as possible.
for (int i = 0; i < lgrp_spaces()->length(); i++) {
MutableSpace *s = lgrp_spaces()->at(i)->space();
LGRPSpace *ls = lgrp_spaces()->at(i);
MutableSpace *s = ls->space();
s->set_end(s->bottom());
s->set_top(s->bottom());
ls->clear_alloc_rate();
}
initialize(region(), true);
// A NUMA space is never mangled
initialize(region(),
SpaceDecorator::Clear,
SpaceDecorator::DontMangle);
} else {
bool should_initialize = false;
if (!os::numa_has_static_binding()) {
@ -257,7 +298,10 @@ void MutableNUMASpace::update() {
if (should_initialize ||
(UseAdaptiveNUMAChunkSizing && adaptation_cycles() < samples_count())) {
initialize(region(), true);
// A NUMA space is never mangled
initialize(region(),
SpaceDecorator::Clear,
SpaceDecorator::DontMangle);
}
}
@ -448,14 +492,17 @@ void MutableNUMASpace::merge_regions(MemRegion new_region, MemRegion* intersecti
}
}
void MutableNUMASpace::initialize(MemRegion mr, bool clear_space) {
void MutableNUMASpace::initialize(MemRegion mr,
bool clear_space,
bool mangle_space) {
assert(clear_space, "Reallocation will destory data!");
assert(lgrp_spaces()->length() > 0, "There should be at least one space");
MemRegion old_region = region(), new_region;
set_bottom(mr.start());
set_end(mr.end());
MutableSpace::set_top(bottom());
// Must always clear the space
clear(SpaceDecorator::DontMangle);
// Compute chunk sizes
size_t prev_page_size = page_size();
@ -586,10 +633,8 @@ void MutableNUMASpace::initialize(MemRegion mr, bool clear_space) {
bias_region(top_region, ls->lgrp_id());
}
// If we clear the region, we would mangle it in debug. That would cause page
// allocation in a different place. Hence setting the top directly.
s->initialize(new_region, false);
s->set_top(s->bottom());
// Clear space (set top = bottom) but never mangle.
s->initialize(new_region, SpaceDecorator::Clear, SpaceDecorator::DontMangle);
set_adaptation_cycles(samples_count());
}
@ -641,10 +686,12 @@ void MutableNUMASpace::set_top(HeapWord* value) {
MutableSpace::set_top(value);
}
void MutableNUMASpace::clear() {
void MutableNUMASpace::clear(bool mangle_space) {
MutableSpace::set_top(bottom());
for (int i = 0; i < lgrp_spaces()->length(); i++) {
lgrp_spaces()->at(i)->space()->clear();
// Never mangle NUMA spaces because the mangling will
// bind the memory to a possibly unwanted lgroup.
lgrp_spaces()->at(i)->space()->clear(SpaceDecorator::DontMangle);
}
}

View File

@ -112,6 +112,7 @@ class MutableNUMASpace : public MutableSpace {
int lgrp_id() const { return _lgrp_id; }
MutableSpace* space() const { return _space; }
AdaptiveWeightedAverage* alloc_rate() const { return _alloc_rate; }
void clear_alloc_rate() { _alloc_rate->clear(); }
SpaceStats* space_stats() { return &_space_stats; }
void clear_space_stats() { _space_stats = SpaceStats(); }
@ -171,14 +172,21 @@ class MutableNUMASpace : public MutableSpace {
MutableNUMASpace();
virtual ~MutableNUMASpace();
// Space initialization.
virtual void initialize(MemRegion mr, bool clear_space);
virtual void initialize(MemRegion mr, bool clear_space, bool mangle_space);
// Update space layout if necessary. Do all adaptive resizing job.
virtual void update();
// Update allocation rate averages.
virtual void accumulate_statistics();
virtual void clear();
virtual void mangle_unused_area();
virtual void clear(bool mangle_space);
virtual void mangle_unused_area() PRODUCT_RETURN;
virtual void mangle_unused_area_complete() PRODUCT_RETURN;
virtual void mangle_region(MemRegion mr) PRODUCT_RETURN;
virtual void check_mangled_unused_area(HeapWord* limit) PRODUCT_RETURN;
virtual void check_mangled_unused_area_complete() PRODUCT_RETURN;
virtual void set_top_for_allocations(HeapWord* v) PRODUCT_RETURN;
virtual void set_top_for_allocations() PRODUCT_RETURN;
virtual void ensure_parsability();
virtual size_t used_in_words() const;
virtual size_t free_in_words() const;

View File

@ -25,7 +25,17 @@
# include "incls/_precompiled.incl"
# include "incls/_mutableSpace.cpp.incl"
void MutableSpace::initialize(MemRegion mr, bool clear_space) {
MutableSpace::MutableSpace(): ImmutableSpace(), _top(NULL) {
_mangler = new MutableSpaceMangler(this);
}
MutableSpace::~MutableSpace() {
delete _mangler;
}
void MutableSpace::initialize(MemRegion mr,
bool clear_space,
bool mangle_space) {
HeapWord* bottom = mr.start();
HeapWord* end = mr.end();
@ -34,13 +44,50 @@ void MutableSpace::initialize(MemRegion mr, bool clear_space) {
set_bottom(bottom);
set_end(end);
if (clear_space) clear();
if (clear_space) {
clear(mangle_space);
}
}
void MutableSpace::clear() {
void MutableSpace::clear(bool mangle_space) {
set_top(bottom());
if (ZapUnusedHeapArea) mangle_unused_area();
if (ZapUnusedHeapArea && mangle_space) {
mangle_unused_area();
}
}
#ifndef PRODUCT
void MutableSpace::check_mangled_unused_area(HeapWord* limit) {
mangler()->check_mangled_unused_area(limit);
}
void MutableSpace::check_mangled_unused_area_complete() {
mangler()->check_mangled_unused_area_complete();
}
// Mangle only the unused space that has not previously
// been mangled and that has not been allocated since being
// mangled.
void MutableSpace::mangle_unused_area() {
mangler()->mangle_unused_area();
}
void MutableSpace::mangle_unused_area_complete() {
mangler()->mangle_unused_area_complete();
}
void MutableSpace::mangle_region(MemRegion mr) {
SpaceMangler::mangle_region(mr);
}
void MutableSpace::set_top_for_allocations(HeapWord* v) {
mangler()->set_top_for_allocations(v);
}
void MutableSpace::set_top_for_allocations() {
mangler()->set_top_for_allocations(top());
}
#endif
// This version requires locking. */
HeapWord* MutableSpace::allocate(size_t size) {

View File

@ -30,14 +30,23 @@
// Invariant: (ImmutableSpace +) bottom() <= top() <= end()
// top() is inclusive and end() is exclusive.
class MutableSpaceMangler;
class MutableSpace: public ImmutableSpace {
friend class VMStructs;
// Helper for mangling unused space in debug builds
MutableSpaceMangler* _mangler;
protected:
HeapWord* _top;
MutableSpaceMangler* mangler() { return _mangler; }
public:
virtual ~MutableSpace() {}
MutableSpace() { _top = NULL; }
virtual ~MutableSpace();
MutableSpace();
// Accessors
HeapWord* top() const { return _top; }
virtual void set_top(HeapWord* value) { _top = value; }
@ -52,21 +61,30 @@ class MutableSpace: public ImmutableSpace {
MemRegion used_region() { return MemRegion(bottom(), top()); }
// Initialization
virtual void initialize(MemRegion mr, bool clear_space);
virtual void clear();
virtual void initialize(MemRegion mr,
bool clear_space,
bool mangle_space);
virtual void clear(bool mangle_space);
// Does the usual initialization but optionally resets top to bottom.
#if 0 // MANGLE_SPACE
void initialize(MemRegion mr, bool clear_space, bool reset_top);
#endif
virtual void update() { }
virtual void accumulate_statistics() { }
// Overwrites the unused portion of this space. Note that some collectors
// may use this "scratch" space during collections.
virtual void mangle_unused_area() {
mangle_region(MemRegion(_top, _end));
}
// Methods used in mangling. See descriptions under SpaceMangler.
virtual void mangle_unused_area() PRODUCT_RETURN;
virtual void mangle_unused_area_complete() PRODUCT_RETURN;
virtual void check_mangled_unused_area(HeapWord* limit) PRODUCT_RETURN;
virtual void check_mangled_unused_area_complete() PRODUCT_RETURN;
virtual void set_top_for_allocations(HeapWord* v) PRODUCT_RETURN;
// Used to save the space's current top for later use during mangling.
virtual void set_top_for_allocations() PRODUCT_RETURN;
virtual void ensure_parsability() { }
void mangle_region(MemRegion mr) {
debug_only(Copy::fill_to_words(mr.start(), mr.word_size(), badHeapWord));
}
virtual void mangle_region(MemRegion mr) PRODUCT_RETURN;
// Boolean querries.
bool is_empty() const { return used_in_words() == 0; }

View File

@ -0,0 +1,140 @@
/*
* Copyright 2002-2005 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
# include "incls/_precompiled.incl"
# include "incls/_spaceDecorator.cpp.incl"
// Catch-all file for utility classes
#ifndef PRODUCT
// Returns true is the location q matches the mangling
// pattern.
bool SpaceMangler::is_mangled(HeapWord* q) {
// This test loses precision but is good enough
return badHeapWord == (max_juint & (uintptr_t) q->value());
}
void SpaceMangler::set_top_for_allocations(HeapWord* v) {
if (v < end()) {
assert(is_mangled(v), "The high water mark is not mangled");
}
_top_for_allocations = v;
}
// Mangle only the unused space that has not previously
// been mangled and that has not been allocated since being
// mangled.
void SpaceMangler::mangle_unused_area() {
assert(ZapUnusedHeapArea, "Mangling should not be in use");
// Mangle between top and the high water mark. Safeguard
// against the space changing since top_for_allocations was
// set.
HeapWord* mangled_end = MIN2(top_for_allocations(), end());
if (top() < mangled_end) {
MemRegion mangle_mr(top(), mangled_end);
SpaceMangler::mangle_region(mangle_mr);
// Light weight check of mangling.
check_mangled_unused_area(end());
}
// Complete check of unused area which is functional when
// DEBUG_MANGLING is defined.
check_mangled_unused_area_complete();
}
// A complete mangle is expected in the
// exceptional case where top_for_allocations is not
// properly tracking the high water mark for mangling.
// This can be the case when to-space is being used for
// scratch space during a mark-sweep-compact. See
// contribute_scratch() and PSMarkSweep::allocate_stacks().
void SpaceMangler::mangle_unused_area_complete() {
assert(ZapUnusedHeapArea, "Mangling should not be in use");
MemRegion mangle_mr(top(), end());
SpaceMangler::mangle_region(mangle_mr);
}
// Simply mangle the MemRegion mr.
void SpaceMangler::mangle_region(MemRegion mr) {
assert(ZapUnusedHeapArea, "Mangling should not be in use");
#ifdef ASSERT
if(TraceZapUnusedHeapArea) {
gclog_or_tty->print("Mangling [0x%x to 0x%x)", mr.start(), mr.end());
}
Copy::fill_to_words(mr.start(), mr.word_size(), badHeapWord);
if(TraceZapUnusedHeapArea) {
gclog_or_tty->print_cr(" done");
}
#endif
}
// Check that top, top_for_allocations and the last
// word of the space are mangled. In a tight memory
// situation even this light weight mangling could
// cause paging by touching the end of the space.
void SpaceMangler::check_mangled_unused_area(HeapWord* limit) {
if (CheckZapUnusedHeapArea) {
// This method can be called while the spaces are
// being reshaped so skip the test if the end of the
// space is beyond the specified limit;
if (end() > limit) return;
assert(top() == end() ||
(is_mangled(top())), "Top not mangled");
assert((top_for_allocations() < top()) ||
(top_for_allocations() >= end()) ||
(is_mangled(top_for_allocations())),
"Older unused not mangled");
assert(top() == end() ||
(is_mangled(end() - 1)), "End not properly mangled");
// Only does checking when DEBUG_MANGLING is defined.
check_mangled_unused_area_complete();
}
}
#undef DEBUG_MANGLING
// This should only be used while debugging the mangling
// because of the high cost of checking the completeness.
void SpaceMangler::check_mangled_unused_area_complete() {
if (CheckZapUnusedHeapArea) {
assert(ZapUnusedHeapArea, "Not mangling unused area");
#ifdef DEBUG_MANGLING
HeapWord* q = top();
HeapWord* limit = end();
bool passed = true;
while (q < limit) {
if (!is_mangled(q)) {
passed = false;
break;
}
q++;
}
assert(passed, "Mangling is not complete");
#endif
}
}
#undef DEBUG_MANGLING
#endif // not PRODUCT

View File

@ -0,0 +1,141 @@
/*
* Copyright 2002-2005 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
class SpaceDecorator: public AllStatic {
public:
// Initialization flags.
static const bool Clear = true;
static const bool DontClear = false;
static const bool Mangle = true;
static const bool DontMangle = false;
};
// Functionality for use with class Space and class MutableSpace.
// The approach taken with the mangling is to mangle all
// the space initially and then to mangle areas that have
// been allocated since the last collection. Mangling is
// done in the context of a generation and in the context
// of a space.
// The space in a generation is mangled when it is first
// initialized and when the generation grows. The spaces
// are not necessarily up-to-date when this mangling occurs
// and the method mangle_region() is used.
// After allocations have been done in a space, the space generally
// need to be remangled. Remangling is only done on the
// recently allocated regions in the space. Typically, that is
// the region between the new top and the top just before a
// garbage collection.
// An exception to the usual mangling in a space is done when the
// space is used for an extraordinary purpose. Specifically, when
// to-space is used as scratch space for a mark-sweep-compact
// collection.
// Spaces are mangled after a collection. If the generation
// grows after a collection, the added space is mangled as part of
// the growth of the generation. No additional mangling is needed when the
// spaces are resized after an expansion.
// The class SpaceMangler keeps a pointer to the top of the allocated
// area and provides the methods for doing the piece meal mangling.
// Methods for doing sparces and full checking of the mangling are
// included. The full checking is done if DEBUG_MANGLING is defined.
// GenSpaceMangler is used with the GenCollectedHeap collectors and
// MutableSpaceMangler is used with the ParallelScavengeHeap collectors.
// These subclasses abstract the differences in the types of spaces used
// by each heap.
class SpaceMangler: public CHeapObj {
friend class VMStructs;
// High water mark for allocations. Typically, the space above
// this point have been mangle previously and don't need to be
// touched again. Space belows this point has been allocated
// and remangling is needed between the current top and this
// high water mark.
HeapWord* _top_for_allocations;
HeapWord* top_for_allocations() { return _top_for_allocations; }
public:
// Setting _top_for_allocations to NULL at initialization
// makes it always below top so that mangling done as part
// of the initialize() call of a space does nothing (as it
// should since the mangling is done as part of the constructor
// for the space.
SpaceMangler() : _top_for_allocations(NULL) {}
// Methods for top and end that delegate to the specific
// space type.
virtual HeapWord* top() const = 0;
virtual HeapWord* end() const = 0;
// Return true if q matches the mangled pattern.
static bool is_mangled(HeapWord* q) PRODUCT_RETURN0;
// Used to save the an address in a space for later use during mangling.
void set_top_for_allocations(HeapWord* v);
// Overwrites the unused portion of this space.
// Mangle only the region not previously mangled [top, top_previously_mangled)
void mangle_unused_area();
// Mangle all the unused region [top, end)
void mangle_unused_area_complete();
// Do some sparse checking on the area that should have been mangled.
void check_mangled_unused_area(HeapWord* limit) PRODUCT_RETURN;
// Do a complete check of the area that should be mangled.
void check_mangled_unused_area_complete() PRODUCT_RETURN;
// Mangle the MemRegion. This is a non-space specific mangler. It
// is used during the initial mangling of a space before the space
// is fully constructed. Also is used when a generation is expanded
// and possibly before the spaces have been reshaped to to the new
// size of the generation.
static void mangle_region(MemRegion mr);
};
class ContiguousSpace;
// For use with GenCollectedHeap's
class GenSpaceMangler: public SpaceMangler {
ContiguousSpace* _sp;
ContiguousSpace* sp() { return _sp; }
HeapWord* top() const { return _sp->top(); }
HeapWord* end() const { return _sp->end(); }
public:
GenSpaceMangler(ContiguousSpace* sp) : SpaceMangler(), _sp(sp) {}
};
// For use with ParallelScavengeHeap's.
class MutableSpaceMangler: public SpaceMangler {
MutableSpace* _sp;
MutableSpace* sp() { return _sp; }
HeapWord* top() const { return _sp->top(); }
HeapWord* end() const { return _sp->end(); }
public:
MutableSpaceMangler(MutableSpace* sp) : SpaceMangler(), _sp(sp) {}
};

View File

@ -1405,6 +1405,7 @@ defNewGeneration.cpp java.hpp
defNewGeneration.cpp oop.inline.hpp
defNewGeneration.cpp referencePolicy.hpp
defNewGeneration.cpp space.inline.hpp
defNewGeneration.cpp spaceDecorator.hpp
defNewGeneration.cpp thread_<os_family>.inline.hpp
defNewGeneration.hpp ageTable.hpp
@ -1789,6 +1790,7 @@ generation.cpp generation.inline.hpp
generation.cpp java.hpp
generation.cpp oop.hpp
generation.cpp oop.inline.hpp
generation.cpp spaceDecorator.hpp
generation.cpp space.inline.hpp
generation.hpp allocation.hpp
@ -3722,6 +3724,7 @@ space.cpp oop.inline2.hpp
space.cpp safepoint.hpp
space.cpp space.hpp
space.cpp space.inline.hpp
space.cpp spaceDecorator.hpp
space.cpp systemDictionary.hpp
space.cpp universe.inline.hpp
space.cpp vmSymbols.hpp
@ -3744,6 +3747,13 @@ space.inline.hpp safepoint.hpp
space.inline.hpp space.hpp
space.inline.hpp universe.hpp
spaceDecorator.hpp globalDefinitions.hpp
spaceDecorator.hpp mutableSpace.hpp
spaceDecorator.hpp space.hpp
spaceDecorator.cpp copy.hpp
spaceDecorator.cpp spaceDecorator.hpp
specialized_oop_closures.cpp ostream.hpp
specialized_oop_closures.cpp specialized_oop_closures.hpp

View File

@ -51,6 +51,7 @@ dump.cpp oop.hpp
dump.cpp oopFactory.hpp
dump.cpp resourceArea.hpp
dump.cpp signature.hpp
dump.cpp spaceDecorator.hpp
dump.cpp symbolTable.hpp
dump.cpp systemDictionary.hpp
dump.cpp vmThread.hpp

View File

@ -172,15 +172,25 @@ DefNewGeneration::DefNewGeneration(ReservedSpace rs,
_to_counters = new CSpaceCounters("s1", 2, _max_survivor_size, _to_space,
_gen_counters);
compute_space_boundaries(0);
compute_space_boundaries(0, SpaceDecorator::Clear, SpaceDecorator::Mangle);
update_counters();
_next_gen = NULL;
_tenuring_threshold = MaxTenuringThreshold;
_pretenure_size_threshold_words = PretenureSizeThreshold >> LogHeapWordSize;
}
void DefNewGeneration::compute_space_boundaries(uintx minimum_eden_size) {
uintx alignment = GenCollectedHeap::heap()->collector_policy()->min_alignment();
void DefNewGeneration::compute_space_boundaries(uintx minimum_eden_size,
bool clear_space,
bool mangle_space) {
uintx alignment =
GenCollectedHeap::heap()->collector_policy()->min_alignment();
// If the spaces are being cleared (only done at heap initialization
// currently), the survivor spaces need not be empty.
// Otherwise, no care is taken for used areas in the survivor spaces
// so check.
assert(clear_space || (to()->is_empty() && from()->is_empty()),
"Initialization of the survivor spaces assumes these are empty");
// Compute sizes
uintx size = _virtual_space.committed_size();
@ -214,16 +224,41 @@ void DefNewGeneration::compute_space_boundaries(uintx minimum_eden_size) {
MemRegion fromMR((HeapWord*)from_start, (HeapWord*)to_start);
MemRegion toMR ((HeapWord*)to_start, (HeapWord*)to_end);
eden()->initialize(edenMR, (minimum_eden_size == 0));
// If minumum_eden_size != 0, we will not have cleared any
// A minimum eden size implies that there is a part of eden that
// is being used and that affects the initialization of any
// newly formed eden.
bool live_in_eden = minimum_eden_size > 0;
// If not clearing the spaces, do some checking to verify that
// the space are already mangled.
if (!clear_space) {
// Must check mangling before the spaces are reshaped. Otherwise,
// the bottom or end of one space may have moved into another
// a failure of the check may not correctly indicate which space
// is not properly mangled.
if (ZapUnusedHeapArea) {
HeapWord* limit = (HeapWord*) _virtual_space.high();
eden()->check_mangled_unused_area(limit);
from()->check_mangled_unused_area(limit);
to()->check_mangled_unused_area(limit);
}
}
// Reset the spaces for their new regions.
eden()->initialize(edenMR,
clear_space && !live_in_eden,
SpaceDecorator::Mangle);
// If clear_space and live_in_eden, we will not have cleared any
// portion of eden above its top. This can cause newly
// expanded space not to be mangled if using ZapUnusedHeapArea.
// We explicitly do such mangling here.
if (ZapUnusedHeapArea && (minimum_eden_size != 0)) {
if (ZapUnusedHeapArea && clear_space && live_in_eden && mangle_space) {
eden()->mangle_unused_area();
}
from()->initialize(fromMR, true);
to()->initialize(toMR , true);
from()->initialize(fromMR, clear_space, mangle_space);
to()->initialize(toMR, clear_space, mangle_space);
// Set next compaction spaces.
eden()->set_next_compaction_space(from());
// The to-space is normally empty before a compaction so need
// not be considered. The exception is during promotion
@ -250,7 +285,16 @@ void DefNewGeneration::swap_spaces() {
bool DefNewGeneration::expand(size_t bytes) {
MutexLocker x(ExpandHeap_lock);
HeapWord* prev_high = (HeapWord*) _virtual_space.high();
bool success = _virtual_space.expand_by(bytes);
if (success && ZapUnusedHeapArea) {
// Mangle newly committed space immediately because it
// can be done here more simply that after the new
// spaces have been computed.
HeapWord* new_high = (HeapWord*) _virtual_space.high();
MemRegion mangle_region(prev_high, new_high);
SpaceMangler::mangle_region(mangle_region);
}
// Do not attempt an expand-to-the reserve size. The
// request should properly observe the maximum size of
@ -262,7 +306,8 @@ bool DefNewGeneration::expand(size_t bytes) {
// value.
if (GC_locker::is_active()) {
if (PrintGC && Verbose) {
gclog_or_tty->print_cr("Garbage collection disabled, expanded heap instead");
gclog_or_tty->print_cr("Garbage collection disabled, "
"expanded heap instead");
}
}
@ -326,16 +371,24 @@ void DefNewGeneration::compute_new_size() {
changed = true;
}
if (changed) {
compute_space_boundaries(eden()->used());
MemRegion cmr((HeapWord*)_virtual_space.low(), (HeapWord*)_virtual_space.high());
// The spaces have already been mangled at this point but
// may not have been cleared (set top = bottom) and should be.
// Mangling was done when the heap was being expanded.
compute_space_boundaries(eden()->used(),
SpaceDecorator::Clear,
SpaceDecorator::DontMangle);
MemRegion cmr((HeapWord*)_virtual_space.low(),
(HeapWord*)_virtual_space.high());
Universe::heap()->barrier_set()->resize_covered_region(cmr);
if (Verbose && PrintGC) {
size_t new_size_after = _virtual_space.committed_size();
size_t eden_size_after = eden()->capacity();
size_t survivor_size_after = from()->capacity();
gclog_or_tty->print("New generation size " SIZE_FORMAT "K->" SIZE_FORMAT "K [eden="
gclog_or_tty->print("New generation size " SIZE_FORMAT "K->"
SIZE_FORMAT "K [eden="
SIZE_FORMAT "K,survivor=" SIZE_FORMAT "K]",
new_size_before/K, new_size_after/K, eden_size_after/K, survivor_size_after/K);
new_size_before/K, new_size_after/K,
eden_size_after/K, survivor_size_after/K);
if (WizardMode) {
gclog_or_tty->print("[allowed " SIZE_FORMAT "K extra for %d threads]",
thread_increase_size/K, threads_count);
@ -480,7 +533,7 @@ void DefNewGeneration::collect(bool full,
ScanWeakRefClosure scan_weak_ref(this);
age_table()->clear();
to()->clear();
to()->clear(SpaceDecorator::Mangle);
gch->rem_set()->prepare_for_younger_refs_iterate(false);
@ -525,8 +578,18 @@ void DefNewGeneration::collect(bool full,
soft_ref_policy, &is_alive, &keep_alive, &evacuate_followers, NULL);
if (!promotion_failed()) {
// Swap the survivor spaces.
eden()->clear();
from()->clear();
eden()->clear(SpaceDecorator::Mangle);
from()->clear(SpaceDecorator::Mangle);
if (ZapUnusedHeapArea) {
// This is now done here because of the piece-meal mangling which
// can check for valid mangling at intermediate points in the
// collection(s). When a minor collection fails to collect
// sufficient space resizing of the young generation can occur
// an redistribute the spaces in the young generation. Mangle
// here so that unzapped regions don't get distributed to
// other spaces.
to()->mangle_unused_area();
}
swap_spaces();
assert(to()->is_empty(), "to space should be empty now");
@ -753,6 +816,15 @@ void DefNewGeneration::contribute_scratch(ScratchBlock*& list, Generation* reque
}
}
void DefNewGeneration::reset_scratch() {
// If contributing scratch in to_space, mangle all of
// to_space if ZapUnusedHeapArea. This is needed because
// top is not maintained while using to-space as scratch.
if (ZapUnusedHeapArea) {
to()->mangle_unused_area_complete();
}
}
bool DefNewGeneration::collection_attempt_is_safe() {
if (!to()->is_empty()) {
return false;
@ -806,11 +878,25 @@ void DefNewGeneration::gc_epilogue(bool full) {
}
}
if (ZapUnusedHeapArea) {
eden()->check_mangled_unused_area_complete();
from()->check_mangled_unused_area_complete();
to()->check_mangled_unused_area_complete();
}
// update the generation and space performance counters
update_counters();
gch->collector_policy()->counters()->update_counters();
}
void DefNewGeneration::record_spaces_top() {
assert(ZapUnusedHeapArea, "Not mangling unused space");
eden()->set_top_for_allocations();
to()->set_top_for_allocations();
from()->set_top_for_allocations();
}
void DefNewGeneration::update_counters() {
if (UsePerfData) {
_eden_counters->update_all();

View File

@ -279,6 +279,9 @@ protected:
virtual void gc_prologue(bool full);
virtual void gc_epilogue(bool full);
// Save the tops for eden, from, and to
virtual void record_spaces_top();
// Doesn't require additional work during GC prologue and epilogue
virtual bool performs_in_place_marking() const { return false; }
@ -299,9 +302,12 @@ protected:
// For non-youngest collection, the DefNewGeneration can contribute
// "to-space".
void contribute_scratch(ScratchBlock*& list, Generation* requestor,
virtual void contribute_scratch(ScratchBlock*& list, Generation* requestor,
size_t max_alloc_words);
// Reset for contribution of "to-space".
virtual void reset_scratch();
// GC support
virtual void compute_new_size();
virtual void collect(bool full,
@ -331,7 +337,12 @@ protected:
void verify(bool allow_dirty);
protected:
void compute_space_boundaries(uintx minimum_eden_size);
// If clear_space is true, clear the survivor spaces. Eden is
// cleared if the minimum size of eden is 0. If mangle_space
// is true, also mangle the space in debug mode.
void compute_space_boundaries(uintx minimum_eden_size,
bool clear_space,
bool mangle_space);
// Scavenge support
void swap_spaces();
};

View File

@ -645,7 +645,7 @@ public:
class ClearSpaceClosure : public SpaceClosure {
public:
void do_space(Space* s) {
s->clear();
s->clear(SpaceDecorator::Mangle);
}
};

View File

@ -465,6 +465,11 @@ void GenCollectedHeap::do_collection(bool full,
_gens[i]->stat_record()->invocations++;
_gens[i]->stat_record()->accumulated_time.start();
// Must be done anew before each collection because
// a previous collection will do mangling and will
// change top of some spaces.
record_gen_tops_before_GC();
if (PrintGC && Verbose) {
gclog_or_tty->print("level=%d invoke=%d size=" SIZE_FORMAT,
i,
@ -1058,6 +1063,12 @@ ScratchBlock* GenCollectedHeap::gather_scratch(Generation* requestor,
return res;
}
void GenCollectedHeap::release_scratch() {
for (int i = 0; i < _n_gens; i++) {
_gens[i]->reset_scratch();
}
}
size_t GenCollectedHeap::large_typearray_limit() {
return gen_policy()->large_typearray_limit();
}
@ -1285,6 +1296,24 @@ void GenCollectedHeap::gc_epilogue(bool full) {
always_do_update_barrier = UseConcMarkSweepGC;
};
#ifndef PRODUCT
class GenGCSaveTopsBeforeGCClosure: public GenCollectedHeap::GenClosure {
private:
public:
void do_generation(Generation* gen) {
gen->record_spaces_top();
}
};
void GenCollectedHeap::record_gen_tops_before_GC() {
if (ZapUnusedHeapArea) {
GenGCSaveTopsBeforeGCClosure blk;
generation_iterate(&blk, false); // not old-to-young.
perm_gen()->record_spaces_top();
}
}
#endif // not PRODUCT
class GenEnsureParsabilityClosure: public GenCollectedHeap::GenClosure {
public:
void do_generation(Generation* gen) {

View File

@ -259,6 +259,9 @@ public:
// be provided are returned as a list of ScratchBlocks, sorted by
// decreasing size.
ScratchBlock* gather_scratch(Generation* requestor, size_t max_alloc_words);
// Allow each generation to reset any scratch space that it has
// contributed as it needs.
void release_scratch();
size_t large_typearray_limit();
@ -482,6 +485,9 @@ private:
bool should_do_concurrent_full_gc(GCCause::Cause cause);
void collect_mostly_concurrent(GCCause::Cause cause);
// Save the tops of the spaces in all generations
void record_gen_tops_before_GC() PRODUCT_RETURN;
protected:
virtual void gc_prologue(bool full);
virtual void gc_epilogue(bool full);

View File

@ -190,6 +190,10 @@ void GenMarkSweep::allocate_stacks() {
void GenMarkSweep::deallocate_stacks() {
GenCollectedHeap* gch = GenCollectedHeap::heap();
gch->release_scratch();
if (_preserved_oop_stack) {
delete _preserved_mark_stack;
_preserved_mark_stack = NULL;

View File

@ -32,6 +32,12 @@ Generation::Generation(ReservedSpace rs, size_t initial_size, int level) :
vm_exit_during_initialization("Could not reserve enough space for "
"object heap");
}
// Mangle all of the the initial generation.
if (ZapUnusedHeapArea) {
MemRegion mangle_region((HeapWord*)_virtual_space.low(),
(HeapWord*)_virtual_space.high());
SpaceMangler::mangle_region(mangle_region);
}
_reserved = MemRegion((HeapWord*)_virtual_space.low_boundary(),
(HeapWord*)_virtual_space.high_boundary());
}
@ -505,8 +511,11 @@ bool OneContigSpaceCardGeneration::grow_by(size_t bytes) {
_bts->resize(new_word_size);
// Fix for bug #4668531
MemRegion mangle_region(_the_space->end(), (HeapWord*)_virtual_space.high());
_the_space->mangle_region(mangle_region);
if (ZapUnusedHeapArea) {
MemRegion mangle_region(_the_space->end(),
(HeapWord*)_virtual_space.high());
SpaceMangler::mangle_region(mangle_region);
}
// Expand space -- also expands space's BOT
// (which uses (part of) shared array above)
@ -622,6 +631,14 @@ void OneContigSpaceCardGeneration::gc_epilogue(bool full) {
// update the generation and space performance counters
update_counters();
if (ZapUnusedHeapArea) {
the_space()->check_mangled_unused_area_complete();
}
}
void OneContigSpaceCardGeneration::record_spaces_top() {
assert(ZapUnusedHeapArea, "Not mangling unused space");
the_space()->set_top_for_allocations();
}
void OneContigSpaceCardGeneration::verify(bool allow_dirty) {

View File

@ -376,6 +376,9 @@ class Generation: public CHeapObj {
// The default is to do nothing.
virtual void gc_epilogue(bool full) {};
// Save the high water marks for the used space in a generation.
virtual void record_spaces_top() {};
// Some generations may need to be "fixed-up" after some allocation
// activity to make them parsable again. The default is to do nothing.
virtual void ensure_parsability() {};
@ -476,6 +479,10 @@ class Generation: public CHeapObj {
virtual void contribute_scratch(ScratchBlock*& list, Generation* requestor,
size_t max_alloc_words) {}
// Give each generation an opportunity to do clean up for any
// contributed scratch.
virtual void reset_scratch() {};
// When an older generation has been collected, and perhaps resized,
// this method will be invoked on all younger generations (from older to
// younger), allowing them to resize themselves as appropriate.
@ -699,6 +706,8 @@ class OneContigSpaceCardGeneration: public CardGeneration {
virtual void gc_epilogue(bool full);
virtual void record_spaces_top();
virtual void verify(bool allow_dirty);
virtual void print_on(outputStream* st) const;
};

View File

@ -232,30 +232,44 @@ ContiguousSpace::new_dcto_cl(OopClosure* cl,
return new ContiguousSpaceDCTOC(this, cl, precision, boundary);
}
void Space::initialize(MemRegion mr, bool clear_space) {
void Space::initialize(MemRegion mr,
bool clear_space,
bool mangle_space) {
HeapWord* bottom = mr.start();
HeapWord* end = mr.end();
assert(Universe::on_page_boundary(bottom) && Universe::on_page_boundary(end),
"invalid space boundaries");
set_bottom(bottom);
set_end(end);
if (clear_space) clear();
if (clear_space) clear(mangle_space);
}
void Space::clear() {
if (ZapUnusedHeapArea) mangle_unused_area();
void Space::clear(bool mangle_space) {
if (ZapUnusedHeapArea && mangle_space) {
mangle_unused_area();
}
}
void ContiguousSpace::initialize(MemRegion mr, bool clear_space)
ContiguousSpace::ContiguousSpace(): CompactibleSpace(), _top(NULL) {
_mangler = new GenSpaceMangler(this);
}
ContiguousSpace::~ContiguousSpace() {
delete _mangler;
}
void ContiguousSpace::initialize(MemRegion mr,
bool clear_space,
bool mangle_space)
{
CompactibleSpace::initialize(mr, clear_space);
CompactibleSpace::initialize(mr, clear_space, mangle_space);
_concurrent_iteration_safe_limit = top();
}
void ContiguousSpace::clear() {
void ContiguousSpace::clear(bool mangle_space) {
set_top(bottom());
set_saved_mark();
Space::clear();
Space::clear(mangle_space);
}
bool Space::is_in(const void* p) const {
@ -271,8 +285,8 @@ bool ContiguousSpace::is_free_block(const HeapWord* p) const {
return p >= _top;
}
void OffsetTableContigSpace::clear() {
ContiguousSpace::clear();
void OffsetTableContigSpace::clear(bool mangle_space) {
ContiguousSpace::clear(mangle_space);
_offsets.initialize_threshold();
}
@ -288,17 +302,46 @@ void OffsetTableContigSpace::set_end(HeapWord* new_end) {
Space::set_end(new_end);
}
#ifndef PRODUCT
void ContiguousSpace::set_top_for_allocations(HeapWord* v) {
mangler()->set_top_for_allocations(v);
}
void ContiguousSpace::set_top_for_allocations() {
mangler()->set_top_for_allocations(top());
}
void ContiguousSpace::check_mangled_unused_area(HeapWord* limit) {
mangler()->check_mangled_unused_area(limit);
}
void ContiguousSpace::check_mangled_unused_area_complete() {
mangler()->check_mangled_unused_area_complete();
}
// Mangled only the unused space that has not previously
// been mangled and that has not been allocated since being
// mangled.
void ContiguousSpace::mangle_unused_area() {
// to-space is used for storing marks during mark-sweep
mangle_region(MemRegion(top(), end()));
mangler()->mangle_unused_area();
}
void ContiguousSpace::mangle_unused_area_complete() {
mangler()->mangle_unused_area_complete();
}
void ContiguousSpace::mangle_region(MemRegion mr) {
debug_only(Copy::fill_to_words(mr.start(), mr.word_size(), badHeapWord));
// Although this method uses SpaceMangler::mangle_region() which
// is not specific to a space, the when the ContiguousSpace version
// is called, it is always with regard to a space and this
// bounds checking is appropriate.
MemRegion space_mr(bottom(), end());
assert(space_mr.contains(mr), "Mangling outside space");
SpaceMangler::mangle_region(mr);
}
#endif // NOT_PRODUCT
void CompactibleSpace::initialize(MemRegion mr, bool clear_space) {
Space::initialize(mr, clear_space);
void CompactibleSpace::initialize(MemRegion mr,
bool clear_space,
bool mangle_space) {
Space::initialize(mr, clear_space, mangle_space);
_compaction_top = bottom();
_next_compaction_space = NULL;
}
@ -820,8 +863,8 @@ void ContiguousSpace::allocate_temporary_filler(int factor) {
}
}
void EdenSpace::clear() {
ContiguousSpace::clear();
void EdenSpace::clear(bool mangle_space) {
ContiguousSpace::clear(mangle_space);
set_soft_end(end());
}
@ -878,7 +921,7 @@ OffsetTableContigSpace::OffsetTableContigSpace(BlockOffsetSharedArray* sharedOff
_par_alloc_lock(Mutex::leaf, "OffsetTableContigSpace par alloc lock", true)
{
_offsets.set_contig_space(this);
initialize(mr, true);
initialize(mr, SpaceDecorator::Clear, SpaceDecorator::Mangle);
}

View File

@ -131,15 +131,17 @@ class Space: public CHeapObj {
return MemRegion(bottom(), saved_mark_word());
}
// Initialization
virtual void initialize(MemRegion mr, bool clear_space);
virtual void clear();
// Initialization. These may be run to reset an existing
// Space.
virtual void initialize(MemRegion mr, bool clear_space, bool mangle_space);
virtual void clear(bool mangle_space);
// For detecting GC bugs. Should only be called at GC boundaries, since
// some unused space may be used as scratch space during GC's.
// Default implementation does nothing. We also call this when expanding
// a space to satisfy an allocation request. See bug #4668531
virtual void mangle_unused_area() {}
virtual void mangle_unused_area_complete() {}
virtual void mangle_region(MemRegion mr) {}
// Testers
@ -354,7 +356,7 @@ private:
CompactibleSpace* _next_compaction_space;
public:
virtual void initialize(MemRegion mr, bool clear_space);
virtual void initialize(MemRegion mr, bool clear_space, bool mangle_space);
// Used temporarily during a compaction phase to hold the value
// top should have when compaction is complete.
@ -724,12 +726,14 @@ protected:
/* continuously, but those that weren't need to have their thresholds */ \
/* re-initialized. Also mangles unused area for debugging. */ \
if (is_empty()) { \
clear(); \
clear(SpaceDecorator::Mangle); \
} else { \
if (ZapUnusedHeapArea) mangle_unused_area(); \
} \
}
class GenSpaceMangler;
// A space in which the free area is contiguous. It therefore supports
// faster allocation, and compaction.
class ContiguousSpace: public CompactibleSpace {
@ -738,13 +742,21 @@ class ContiguousSpace: public CompactibleSpace {
protected:
HeapWord* _top;
HeapWord* _concurrent_iteration_safe_limit;
// A helper for mangling the unused area of the space in debug builds.
GenSpaceMangler* _mangler;
GenSpaceMangler* mangler() { return _mangler; }
// Allocation helpers (return NULL if full).
inline HeapWord* allocate_impl(size_t word_size, HeapWord* end_value);
inline HeapWord* par_allocate_impl(size_t word_size, HeapWord* end_value);
public:
virtual void initialize(MemRegion mr, bool clear_space);
ContiguousSpace();
~ContiguousSpace();
virtual void initialize(MemRegion mr, bool clear_space, bool mangle_space);
// Accessors
HeapWord* top() const { return _top; }
@ -753,15 +765,34 @@ class ContiguousSpace: public CompactibleSpace {
void set_saved_mark() { _saved_mark_word = top(); }
void reset_saved_mark() { _saved_mark_word = bottom(); }
virtual void clear();
virtual void clear(bool mangle_space);
WaterMark bottom_mark() { return WaterMark(this, bottom()); }
WaterMark top_mark() { return WaterMark(this, top()); }
WaterMark saved_mark() { return WaterMark(this, saved_mark_word()); }
bool saved_mark_at_top() const { return saved_mark_word() == top(); }
void mangle_unused_area();
void mangle_region(MemRegion mr);
// In debug mode mangle (write it with a particular bit
// pattern) the unused part of a space.
// Used to save the an address in a space for later use during mangling.
void set_top_for_allocations(HeapWord* v) PRODUCT_RETURN;
// Used to save the space's current top for later use during mangling.
void set_top_for_allocations() PRODUCT_RETURN;
// Mangle regions in the space from the current top up to the
// previously mangled part of the space.
void mangle_unused_area() PRODUCT_RETURN;
// Mangle [top, end)
void mangle_unused_area_complete() PRODUCT_RETURN;
// Mangle the given MemRegion.
void mangle_region(MemRegion mr) PRODUCT_RETURN;
// Do some sparse checking on the area that should have been mangled.
void check_mangled_unused_area(HeapWord* limit) PRODUCT_RETURN;
// Check the complete area that should have been mangled.
// This code may be NULL depending on the macro DEBUG_MANGLING.
void check_mangled_unused_area_complete() PRODUCT_RETURN;
// Size computations: sizes in bytes.
size_t capacity() const { return byte_size(bottom(), end()); }
@ -956,7 +987,7 @@ class EdenSpace : public ContiguousSpace {
void set_soft_end(HeapWord* value) { _soft_end = value; }
// Override.
void clear();
void clear(bool mangle_space);
// Set both the 'hard' and 'soft' limits (_end and _soft_end).
void set_end(HeapWord* value) {
@ -1000,7 +1031,7 @@ class OffsetTableContigSpace: public ContiguousSpace {
void set_bottom(HeapWord* value);
void set_end(HeapWord* value);
void clear();
void clear(bool mangle_space);
inline HeapWord* block_start(const void* p) const;

View File

@ -589,9 +589,15 @@ class CommandLineFlags {
develop(bool, ZapJNIHandleArea, trueInDebug, \
"Zap freed JNI handle space with 0xFEFEFEFE") \
\
develop(bool, ZapUnusedHeapArea, false, \
develop(bool, ZapUnusedHeapArea, trueInDebug, \
"Zap unused heap space with 0xBAADBABE") \
\
develop(bool, TraceZapUnusedHeapArea, false, \
"Trace zapping of unused heap space") \
\
develop(bool, CheckZapUnusedHeapArea, false, \
"Check zapping of unused heap space") \
\
develop(bool, PrintVMMessages, true, \
"Print vm messages on console") \
\

View File

@ -99,6 +99,10 @@ class HeapWord {
friend class VMStructs;
private:
char* i;
#ifdef ASSERT
public:
char* value() { return i; }
#endif
};
// HeapWordSize must be 2^LogHeapWordSize.