提交 c4b16995 编写于 作者: Y ysr

6824570: ParNew: Fix memory leak introduced in 6819891

Summary: Allocate worker-local overflow stacks, introduced in 6819891, along with ParNewGeneration, rather than with the per-scavenge ParScanThreadState.
Reviewed-by: jmasa
上级 393ae332
...@@ -34,10 +34,12 @@ ParScanThreadState::ParScanThreadState(Space* to_space_, ...@@ -34,10 +34,12 @@ ParScanThreadState::ParScanThreadState(Space* to_space_,
Generation* old_gen_, Generation* old_gen_,
int thread_num_, int thread_num_,
ObjToScanQueueSet* work_queue_set_, ObjToScanQueueSet* work_queue_set_,
GrowableArray<oop>** overflow_stack_set_,
size_t desired_plab_sz_, size_t desired_plab_sz_,
ParallelTaskTerminator& term_) : ParallelTaskTerminator& term_) :
_to_space(to_space_), _old_gen(old_gen_), _young_gen(gen_), _thread_num(thread_num_), _to_space(to_space_), _old_gen(old_gen_), _young_gen(gen_), _thread_num(thread_num_),
_work_queue(work_queue_set_->queue(thread_num_)), _to_space_full(false), _work_queue(work_queue_set_->queue(thread_num_)), _to_space_full(false),
_overflow_stack(overflow_stack_set_[thread_num_]),
_ageTable(false), // false ==> not the global age table, no perf data. _ageTable(false), // false ==> not the global age table, no perf data.
_to_space_alloc_buffer(desired_plab_sz_), _to_space_alloc_buffer(desired_plab_sz_),
_to_space_closure(gen_, this), _old_gen_closure(gen_, this), _to_space_closure(gen_, this), _old_gen_closure(gen_, this),
...@@ -57,11 +59,6 @@ ParScanThreadState::ParScanThreadState(Space* to_space_, ...@@ -57,11 +59,6 @@ ParScanThreadState::ParScanThreadState(Space* to_space_,
_start = os::elapsedTime(); _start = os::elapsedTime();
_old_gen_closure.set_generation(old_gen_); _old_gen_closure.set_generation(old_gen_);
_old_gen_root_closure.set_generation(old_gen_); _old_gen_root_closure.set_generation(old_gen_);
if (UseCompressedOops) {
_overflow_stack = new (ResourceObj::C_HEAP) GrowableArray<oop>(512, true);
} else {
_overflow_stack = NULL;
}
} }
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( pop ) #pragma warning( pop )
...@@ -155,7 +152,7 @@ void ParScanThreadState::trim_queues(int max_size) { ...@@ -155,7 +152,7 @@ void ParScanThreadState::trim_queues(int max_size) {
} }
bool ParScanThreadState::take_from_overflow_stack() { bool ParScanThreadState::take_from_overflow_stack() {
assert(UseCompressedOops, "Else should not call"); assert(ParGCUseLocalOverflow, "Else should not call");
assert(young_gen()->overflow_list() == NULL, "Error"); assert(young_gen()->overflow_list() == NULL, "Error");
ObjToScanQueue* queue = work_queue(); ObjToScanQueue* queue = work_queue();
GrowableArray<oop>* of_stack = overflow_stack(); GrowableArray<oop>* of_stack = overflow_stack();
...@@ -183,7 +180,7 @@ bool ParScanThreadState::take_from_overflow_stack() { ...@@ -183,7 +180,7 @@ bool ParScanThreadState::take_from_overflow_stack() {
} }
void ParScanThreadState::push_on_overflow_stack(oop p) { void ParScanThreadState::push_on_overflow_stack(oop p) {
assert(UseCompressedOops, "Else should not call"); assert(ParGCUseLocalOverflow, "Else should not call");
overflow_stack()->push(p); overflow_stack()->push(p);
assert(young_gen()->overflow_list() == NULL, "Error"); assert(young_gen()->overflow_list() == NULL, "Error");
} }
...@@ -260,6 +257,7 @@ public: ...@@ -260,6 +257,7 @@ public:
ParNewGeneration& gen, ParNewGeneration& gen,
Generation& old_gen, Generation& old_gen,
ObjToScanQueueSet& queue_set, ObjToScanQueueSet& queue_set,
GrowableArray<oop>** overflow_stacks_,
size_t desired_plab_sz, size_t desired_plab_sz,
ParallelTaskTerminator& term); ParallelTaskTerminator& term);
inline ParScanThreadState& thread_sate(int i); inline ParScanThreadState& thread_sate(int i);
...@@ -282,6 +280,7 @@ private: ...@@ -282,6 +280,7 @@ private:
ParScanThreadStateSet::ParScanThreadStateSet( ParScanThreadStateSet::ParScanThreadStateSet(
int num_threads, Space& to_space, ParNewGeneration& gen, int num_threads, Space& to_space, ParNewGeneration& gen,
Generation& old_gen, ObjToScanQueueSet& queue_set, Generation& old_gen, ObjToScanQueueSet& queue_set,
GrowableArray<oop>** overflow_stack_set_,
size_t desired_plab_sz, ParallelTaskTerminator& term) size_t desired_plab_sz, ParallelTaskTerminator& term)
: ResourceArray(sizeof(ParScanThreadState), num_threads), : ResourceArray(sizeof(ParScanThreadState), num_threads),
_gen(gen), _next_gen(old_gen), _term(term), _gen(gen), _next_gen(old_gen), _term(term),
...@@ -292,7 +291,7 @@ ParScanThreadStateSet::ParScanThreadStateSet( ...@@ -292,7 +291,7 @@ ParScanThreadStateSet::ParScanThreadStateSet(
for (int i = 0; i < num_threads; ++i) { for (int i = 0; i < num_threads; ++i) {
new ((ParScanThreadState*)_data + i) new ((ParScanThreadState*)_data + i)
ParScanThreadState(&to_space, &gen, &old_gen, i, &queue_set, ParScanThreadState(&to_space, &gen, &old_gen, i, &queue_set,
desired_plab_sz, term); overflow_stack_set_, desired_plab_sz, term);
} }
} }
...@@ -519,6 +518,17 @@ ParNewGeneration(ReservedSpace rs, size_t initial_byte_size, int level) ...@@ -519,6 +518,17 @@ ParNewGeneration(ReservedSpace rs, size_t initial_byte_size, int level)
for (uint i2 = 0; i2 < ParallelGCThreads; i2++) for (uint i2 = 0; i2 < ParallelGCThreads; i2++)
_task_queues->queue(i2)->initialize(); _task_queues->queue(i2)->initialize();
_overflow_stacks = NEW_C_HEAP_ARRAY(GrowableArray<oop>*, ParallelGCThreads);
guarantee(_overflow_stacks != NULL, "Overflow stack set allocation failure");
for (uint i = 0; i < ParallelGCThreads; i++) {
if (ParGCUseLocalOverflow) {
_overflow_stacks[i] = new (ResourceObj::C_HEAP) GrowableArray<oop>(512, true);
guarantee(_overflow_stacks[i] != NULL, "Overflow Stack allocation failure.");
} else {
_overflow_stacks[i] = NULL;
}
}
if (UsePerfData) { if (UsePerfData) {
EXCEPTION_MARK; EXCEPTION_MARK;
ResourceMark rm; ResourceMark rm;
...@@ -784,7 +794,7 @@ void ParNewGeneration::collect(bool full, ...@@ -784,7 +794,7 @@ void ParNewGeneration::collect(bool full,
ParallelTaskTerminator _term(workers->total_workers(), task_queues()); ParallelTaskTerminator _term(workers->total_workers(), task_queues());
ParScanThreadStateSet thread_state_set(workers->total_workers(), ParScanThreadStateSet thread_state_set(workers->total_workers(),
*to(), *this, *_next_gen, *task_queues(), *to(), *this, *_next_gen, *task_queues(),
desired_plab_sz(), _term); _overflow_stacks, desired_plab_sz(), _term);
ParNewGenTask tsk(this, _next_gen, reserved().end(), &thread_state_set); ParNewGenTask tsk(this, _next_gen, reserved().end(), &thread_state_set);
int n_workers = workers->total_workers(); int n_workers = workers->total_workers();
...@@ -1238,11 +1248,12 @@ bool ParNewGeneration::should_simulate_overflow() { ...@@ -1238,11 +1248,12 @@ bool ParNewGeneration::should_simulate_overflow() {
#define BUSY (oop(0x1aff1aff)) #define BUSY (oop(0x1aff1aff))
void ParNewGeneration::push_on_overflow_list(oop from_space_obj, ParScanThreadState* par_scan_state) { void ParNewGeneration::push_on_overflow_list(oop from_space_obj, ParScanThreadState* par_scan_state) {
assert(is_in_reserved(from_space_obj), "Should be from this generation"); assert(is_in_reserved(from_space_obj), "Should be from this generation");
if (UseCompressedOops) { if (ParGCUseLocalOverflow) {
// In the case of compressed oops, we use a private, not-shared // In the case of compressed oops, we use a private, not-shared
// overflow stack. // overflow stack.
par_scan_state->push_on_overflow_stack(from_space_obj); par_scan_state->push_on_overflow_stack(from_space_obj);
} else { } else {
assert(!UseCompressedOops, "Error");
// if the object has been forwarded to itself, then we cannot // if the object has been forwarded to itself, then we cannot
// use the klass pointer for the linked list. Instead we have // use the klass pointer for the linked list. Instead we have
// to allocate an oopDesc in the C-Heap and use that for the linked list. // to allocate an oopDesc in the C-Heap and use that for the linked list.
...@@ -1275,9 +1286,10 @@ void ParNewGeneration::push_on_overflow_list(oop from_space_obj, ParScanThreadSt ...@@ -1275,9 +1286,10 @@ void ParNewGeneration::push_on_overflow_list(oop from_space_obj, ParScanThreadSt
bool ParNewGeneration::take_from_overflow_list(ParScanThreadState* par_scan_state) { bool ParNewGeneration::take_from_overflow_list(ParScanThreadState* par_scan_state) {
bool res; bool res;
if (UseCompressedOops) { if (ParGCUseLocalOverflow) {
res = par_scan_state->take_from_overflow_stack(); res = par_scan_state->take_from_overflow_stack();
} else { } else {
assert(!UseCompressedOops, "Error");
res = take_from_overflow_list_work(par_scan_state); res = take_from_overflow_list_work(par_scan_state);
} }
return res; return res;
...@@ -1305,6 +1317,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan ...@@ -1305,6 +1317,7 @@ bool ParNewGeneration::take_from_overflow_list_work(ParScanThreadState* par_scan
(size_t)ParGCDesiredObjsFromOverflowList); (size_t)ParGCDesiredObjsFromOverflowList);
assert(par_scan_state->overflow_stack() == NULL, "Error"); assert(par_scan_state->overflow_stack() == NULL, "Error");
assert(!UseCompressedOops, "Error");
if (_overflow_list == NULL) return false; if (_overflow_list == NULL) return false;
// Otherwise, there was something there; try claiming the list. // Otherwise, there was something there; try claiming the list.
......
...@@ -33,8 +33,8 @@ class ParEvacuateFollowersClosure; ...@@ -33,8 +33,8 @@ class ParEvacuateFollowersClosure;
// but they must be here to allow ParScanClosure::do_oop_work to be defined // but they must be here to allow ParScanClosure::do_oop_work to be defined
// in genOopClosures.inline.hpp. // in genOopClosures.inline.hpp.
typedef OopTaskQueue ObjToScanQueue; typedef OopTaskQueue ObjToScanQueue;
typedef OopTaskQueueSet ObjToScanQueueSet; typedef OopTaskQueueSet ObjToScanQueueSet;
// Enable this to get push/pop/steal stats. // Enable this to get push/pop/steal stats.
const int PAR_STATS_ENABLED = 0; const int PAR_STATS_ENABLED = 0;
...@@ -116,7 +116,9 @@ class ParScanThreadState { ...@@ -116,7 +116,9 @@ class ParScanThreadState {
ParScanThreadState(Space* to_space_, ParNewGeneration* gen_, ParScanThreadState(Space* to_space_, ParNewGeneration* gen_,
Generation* old_gen_, int thread_num_, Generation* old_gen_, int thread_num_,
ObjToScanQueueSet* work_queue_set_, size_t desired_plab_sz_, ObjToScanQueueSet* work_queue_set_,
GrowableArray<oop>** overflow_stack_set_,
size_t desired_plab_sz_,
ParallelTaskTerminator& term_); ParallelTaskTerminator& term_);
public: public:
...@@ -296,9 +298,12 @@ class ParNewGeneration: public DefNewGeneration { ...@@ -296,9 +298,12 @@ class ParNewGeneration: public DefNewGeneration {
char pad[64 - sizeof(ObjToScanQueue)]; // prevent false sharing char pad[64 - sizeof(ObjToScanQueue)]; // prevent false sharing
}; };
// The per-thread work queues, available here for stealing. // The per-worker-thread work queues
ObjToScanQueueSet* _task_queues; ObjToScanQueueSet* _task_queues;
// Per-worker-thread local overflow stacks
GrowableArray<oop>** _overflow_stacks;
// Desired size of survivor space plab's // Desired size of survivor space plab's
PLABStats _plab_stats; PLABStats _plab_stats;
......
...@@ -971,7 +971,7 @@ void Arguments::set_parnew_gc_flags() { ...@@ -971,7 +971,7 @@ void Arguments::set_parnew_gc_flags() {
} else { } else {
no_shared_spaces(); no_shared_spaces();
// By default YoungPLABSize and OldPLABSize are set to 4096 and 1024 correspondinly, // By default YoungPLABSize and OldPLABSize are set to 4096 and 1024 respectively,
// these settings are default for Parallel Scavenger. For ParNew+Tenured configuration // these settings are default for Parallel Scavenger. For ParNew+Tenured configuration
// we set them to 1024 and 1024. // we set them to 1024 and 1024.
// See CR 6362902. // See CR 6362902.
...@@ -987,6 +987,16 @@ void Arguments::set_parnew_gc_flags() { ...@@ -987,6 +987,16 @@ void Arguments::set_parnew_gc_flags() {
if (AlwaysTenure) { if (AlwaysTenure) {
FLAG_SET_CMDLINE(intx, MaxTenuringThreshold, 0); FLAG_SET_CMDLINE(intx, MaxTenuringThreshold, 0);
} }
// When using compressed oops, we use local overflow stacks,
// rather than using a global overflow list chained through
// the klass word of the object's pre-image.
if (UseCompressedOops && !ParGCUseLocalOverflow) {
if (!FLAG_IS_DEFAULT(ParGCUseLocalOverflow)) {
warning("Forcing +ParGCUseLocalOverflow: needed if using compressed references");
}
FLAG_SET_DEFAULT(ParGCUseLocalOverflow, true);
}
assert(ParGCUseLocalOverflow || !UseCompressedOops, "Error");
} }
} }
......
...@@ -1316,8 +1316,11 @@ class CommandLineFlags { ...@@ -1316,8 +1316,11 @@ class CommandLineFlags {
product(intx, ParGCArrayScanChunk, 50, \ product(intx, ParGCArrayScanChunk, 50, \
"Scan a subset and push remainder, if array is bigger than this") \ "Scan a subset and push remainder, if array is bigger than this") \
\ \
product(bool, ParGCUseLocalOverflow, false, \
"Instead of a global overflow list, use local overflow stacks") \
\
product(bool, ParGCTrimOverflow, true, \ product(bool, ParGCTrimOverflow, true, \
"Eagerly trim the overflow lists (useful for UseCompressedOops") \ "Eagerly trim the local overflow lists (when ParGCUseLocalOverflow") \
\ \
notproduct(bool, ParGCWorkQueueOverflowALot, false, \ notproduct(bool, ParGCWorkQueueOverflowALot, false, \
"Whether we should simulate work queue overflow in ParNew") \ "Whether we should simulate work queue overflow in ParNew") \
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册