Skip to content
Permalink
Browse files
8276696: ParallelObjectIterator freed at the wrong time in VM_HeapDumper
Reviewed-by: pliden, stefank
  • Loading branch information
fisk committed Nov 23, 2021
1 parent 90f96fb commit f4dc03ea6de327425ff265c3d2ec16ea7b0e1634
Showing 15 changed files with 59 additions and 35 deletions.
@@ -2260,7 +2260,7 @@ void G1CollectedHeap::object_iterate(ObjectClosure* cl) {
heap_region_iterate(&blk);
}

class G1ParallelObjectIterator : public ParallelObjectIterator {
class G1ParallelObjectIterator : public ParallelObjectIteratorImpl {
private:
G1CollectedHeap* _heap;
HeapRegionClaimer _claimer;
@@ -2275,7 +2275,7 @@ class G1ParallelObjectIterator : public ParallelObjectIterator {
}
};

ParallelObjectIterator* G1CollectedHeap::parallel_object_iterator(uint thread_num) {
ParallelObjectIteratorImpl* G1CollectedHeap::parallel_object_iterator(uint thread_num) {
return new G1ParallelObjectIterator(thread_num);
}

@@ -1077,7 +1077,7 @@ class G1CollectedHeap : public CollectedHeap {
// Iterate over all objects, calling "cl.do_object" on each.
void object_iterate(ObjectClosure* cl) override;

ParallelObjectIterator* parallel_object_iterator(uint thread_num) override;
ParallelObjectIteratorImpl* parallel_object_iterator(uint thread_num) override;

// Keep alive an object that was loaded with AS_NO_KEEPALIVE.
void keep_alive(oop obj) override;
@@ -600,7 +600,7 @@ void ParallelScavengeHeap::object_iterate_parallel(ObjectClosure* cl,
}
}

class PSScavengeParallelObjectIterator : public ParallelObjectIterator {
class PSScavengeParallelObjectIterator : public ParallelObjectIteratorImpl {
private:
ParallelScavengeHeap* _heap;
HeapBlockClaimer _claimer;
@@ -615,7 +615,7 @@ class PSScavengeParallelObjectIterator : public ParallelObjectIterator {
}
};

ParallelObjectIterator* ParallelScavengeHeap::parallel_object_iterator(uint thread_num) {
ParallelObjectIteratorImpl* ParallelScavengeHeap::parallel_object_iterator(uint thread_num) {
return new PSScavengeParallelObjectIterator();
}

@@ -231,7 +231,7 @@ class ParallelScavengeHeap : public CollectedHeap {

void object_iterate(ObjectClosure* cl);
void object_iterate_parallel(ObjectClosure* cl, HeapBlockClaimer* claimer);
virtual ParallelObjectIterator* parallel_object_iterator(uint thread_num);
virtual ParallelObjectIteratorImpl* parallel_object_iterator(uint thread_num);

HeapWord* block_start(const void* addr) const;
bool block_is_obj(const HeapWord* addr) const;
@@ -110,6 +110,18 @@ void GCHeapLog::log_heap(CollectedHeap* heap, bool before) {
st.print_cr("}");
}

ParallelObjectIterator::ParallelObjectIterator(uint thread_num) :
_impl(Universe::heap()->parallel_object_iterator(thread_num))
{}

ParallelObjectIterator::~ParallelObjectIterator() {
delete _impl;
}

void ParallelObjectIterator::object_iterate(ObjectClosure* cl, uint worker_id) {
_impl->object_iterate(cl, worker_id);
}

size_t CollectedHeap::unused() const {
MutexLocker ml(Heap_lock);
return capacity() - used();
@@ -62,10 +62,23 @@ class VirtualSpaceSummary;
class WorkerThreads;
class nmethod;

class ParallelObjectIterator : public CHeapObj<mtGC> {
class ParallelObjectIteratorImpl : public CHeapObj<mtGC> {
public:
virtual ~ParallelObjectIteratorImpl() {}
virtual void object_iterate(ObjectClosure* cl, uint worker_id) = 0;
virtual ~ParallelObjectIterator() {}
};

// User facing parallel object iterator. This is a StackObj, which ensures that
// the _impl is allocated and deleted in the scope of this object. This ensures
// the life cycle of the implementation is as required by ThreadsListHandle,
// which is sometimes used by the root iterators.
class ParallelObjectIterator : public StackObj {
ParallelObjectIteratorImpl* _impl;

public:
ParallelObjectIterator(uint thread_num);
~ParallelObjectIterator();
void object_iterate(ObjectClosure* cl, uint worker_id);
};

//
@@ -82,6 +95,7 @@ class CollectedHeap : public CHeapObj<mtInternal> {
friend class JVMCIVMStructs;
friend class IsGCActiveMark; // Block structured external access to _is_gc_active
friend class MemAllocator;
friend class ParallelObjectIterator;

private:
GCHeapLog* _gc_heap_log;
@@ -384,10 +398,12 @@ class CollectedHeap : public CHeapObj<mtInternal> {
// Iterate over all objects, calling "cl.do_object" on each.
virtual void object_iterate(ObjectClosure* cl) = 0;

virtual ParallelObjectIterator* parallel_object_iterator(uint thread_num) {
protected:
virtual ParallelObjectIteratorImpl* parallel_object_iterator(uint thread_num) {
return NULL;
}

public:
// Keep alive an object that was loaded with AS_NO_KEEPALIVE.
virtual void keep_alive(oop obj) {}

@@ -1366,7 +1366,7 @@ class ShenandoahObjectIterateParScanClosure : public BasicOopIterateClosure {
// parallel marking queues.
// Every worker processes it's own marking queue. work-stealing is used
// to balance workload.
class ShenandoahParallelObjectIterator : public ParallelObjectIterator {
class ShenandoahParallelObjectIterator : public ParallelObjectIteratorImpl {
private:
uint _num_workers;
bool _init_ready;
@@ -1465,7 +1465,7 @@ class ShenandoahParallelObjectIterator : public ParallelObjectIterator {
}
};

ParallelObjectIterator* ShenandoahHeap::parallel_object_iterator(uint workers) {
ParallelObjectIteratorImpl* ShenandoahHeap::parallel_object_iterator(uint workers) {
return new ShenandoahParallelObjectIterator(workers, &_aux_bit_map);
}

@@ -484,7 +484,7 @@ class ShenandoahHeap : public CollectedHeap {
// Used for native heap walkers: heap dumpers, mostly
void object_iterate(ObjectClosure* cl);
// Parallel heap iteration support
virtual ParallelObjectIterator* parallel_object_iterator(uint workers);
virtual ParallelObjectIteratorImpl* parallel_object_iterator(uint workers);

// Keep alive an object that was loaded with AS_NO_KEEPALIVE.
void keep_alive(oop obj);
@@ -226,7 +226,7 @@ void ZCollectedHeap::object_iterate(ObjectClosure* cl) {
_heap.object_iterate(cl, true /* visit_weaks */);
}

ParallelObjectIterator* ZCollectedHeap::parallel_object_iterator(uint nworkers) {
ParallelObjectIteratorImpl* ZCollectedHeap::parallel_object_iterator(uint nworkers) {
return _heap.parallel_object_iterator(nworkers, true /* visit_weaks */);
}

@@ -95,7 +95,7 @@ class ZCollectedHeap : public CollectedHeap {
virtual GrowableArray<MemoryPool*> memory_pools();

virtual void object_iterate(ObjectClosure* cl);
virtual ParallelObjectIterator* parallel_object_iterator(uint nworkers);
virtual ParallelObjectIteratorImpl* parallel_object_iterator(uint nworkers);

virtual void keep_alive(oop obj);

@@ -439,7 +439,7 @@ void ZHeap::object_iterate(ObjectClosure* cl, bool visit_weaks) {
iter.object_iterate(cl, 0 /* worker_id */);
}

ParallelObjectIterator* ZHeap::parallel_object_iterator(uint nworkers, bool visit_weaks) {
ParallelObjectIteratorImpl* ZHeap::parallel_object_iterator(uint nworkers, bool visit_weaks) {
assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint");
return new ZHeapIterator(nworkers, visit_weaks);
}
@@ -141,7 +141,7 @@ class ZHeap {

// Iteration
void object_iterate(ObjectClosure* cl, bool visit_weaks);
ParallelObjectIterator* parallel_object_iterator(uint nworkers, bool visit_weaks);
ParallelObjectIteratorImpl* parallel_object_iterator(uint nworkers, bool visit_weaks);
void pages_do(ZPageClosure* cl);

// Serviceability
@@ -42,7 +42,7 @@ using ZHeapIteratorQueues = GenericTaskQueueSet<ZHeapIteratorQueue, mtGC>;
using ZHeapIteratorArrayQueue = OverflowTaskQueue<ObjArrayTask, mtGC>;
using ZHeapIteratorArrayQueues = GenericTaskQueueSet<ZHeapIteratorArrayQueue, mtGC>;

class ZHeapIterator : public ParallelObjectIterator {
class ZHeapIterator : public ParallelObjectIteratorImpl {
friend class ZHeapIteratorContext;

private:
@@ -578,18 +578,12 @@ uintx HeapInspection::populate_table(KlassInfoTable* cit, BoolObjectClosure *fil
const uint capped_parallel_thread_num = MIN2(parallel_thread_num, workers->max_workers());
WithActiveWorkers with_active_workers(workers, capped_parallel_thread_num);

ParallelObjectIterator* poi = Universe::heap()->parallel_object_iterator(workers->active_workers());
if (poi != NULL) {
// The GC supports parallel object iteration.

ParHeapInspectTask task(poi, cit, filter);
// Run task with the active workers.
workers->run_task(&task);

delete poi;
if (task.success()) {
return task.missed_count();
}
ParallelObjectIterator poi(workers->active_workers());
ParHeapInspectTask task(&poi, cit, filter);
// Run task with the active workers.
workers->run_task(&task);
if (task.success()) {
return task.missed_count();
}
}
}
@@ -1910,7 +1910,6 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask {
// Number of dumper threads that only iterate heap.
uint _heap_only_dumper_threads = _num_dumper_threads - 1 /* VMDumper thread */;
_dumper_controller = new (std::nothrow) DumperController(_heap_only_dumper_threads);
_poi = Universe::heap()->parallel_object_iterator(_num_dumper_threads);
}
}

@@ -1999,10 +1998,6 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask {
}
FREE_C_HEAP_ARRAY(ThreadStackTrace*, _stack_traces);
}
if (_poi != NULL) {
delete _poi;
_poi = NULL;
}
if (_dumper_controller != NULL) {
delete _dumper_controller;
_dumper_controller = NULL;
@@ -2252,7 +2247,14 @@ void VM_HeapDumper::doit() {
work(0);
} else {
prepare_parallel_dump(workers->active_workers());
workers->run_task(this);
if (_num_dumper_threads > 1) {
ParallelObjectIterator poi(_num_dumper_threads);
_poi = &poi;
workers->run_task(this);
_poi = NULL;
} else {
workers->run_task(this);
}
finish_parallel_dump();
}

1 comment on commit f4dc03e

@openjdk-notifier
Copy link

@openjdk-notifier openjdk-notifier bot commented on f4dc03e Nov 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.