1 Star 0 Fork 72

yangxin/openjdk-11

forked from src-openEuler/openjdk-11 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
8214535-support-Jmap-parallel.patch 32.81 KB
一键复制 编辑 原始数据 按行查看 历史
胡波道 提交于 2021-05-14 11:51 +08:00 . I3R9YJ: update to JDK11.0.11
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858
From 65e9f0b4c719146b0958cb3c01fd31e11e49ec37 Mon Sep 17 00:00:00 2001
Date: Tue, 16 Mar 2021 07:09:57 +0000
Subject: [PATCH 4/4] backport JDK-8214535 to support Jmap parallel
---
src/hotspot/share/gc/g1/g1CollectedHeap.cpp | 25 ++++
src/hotspot/share/gc/g1/g1CollectedHeap.hpp | 4 +
.../gc/parallel/parallelScavengeHeap.cpp | 64 +++++++++++
.../gc/parallel/parallelScavengeHeap.hpp | 22 +++-
src/hotspot/share/gc/parallel/psOldGen.cpp | 32 ++++++
src/hotspot/share/gc/parallel/psOldGen.hpp | 11 ++
src/hotspot/share/gc/shared/collectedHeap.hpp | 11 ++
.../share/gc/shared/vmGCOperations.cpp | 2 +-
.../share/gc/shared/vmGCOperations.hpp | 5 +-
src/hotspot/share/gc/shared/workgroup.hpp | 21 ++++
src/hotspot/share/memory/heapInspection.cpp | 108 ++++++++++++++++--
src/hotspot/share/memory/heapInspection.hpp | 44 ++++++-
src/hotspot/share/runtime/arguments.hpp | 12 +-
src/hotspot/share/services/attachListener.cpp | 15 ++-
.../share/classes/sun/tools/jmap/JMap.java | 41 +++++--
test/jdk/sun/tools/jmap/BasicJMapTest.java | 55 +++++++++
16 files changed, 442 insertions(+), 30 deletions(-)
diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
index 7e9c6254c..fd2da14a3 100644
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
@@ -77,6 +77,7 @@
#include "gc/shared/weakProcessor.hpp"
#include "logging/log.hpp"
#include "memory/allocation.hpp"
+#include "memory/heapInspection.hpp"
#include "memory/iterator.hpp"
#include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp"
@@ -2208,6 +2209,30 @@ void G1CollectedHeap::object_iterate(ObjectClosure* cl) {
heap_region_iterate(&blk);
}
+class G1ParallelObjectIterator : public ParallelObjectIterator {
+private:
+ G1CollectedHeap* _heap;
+ HeapRegionClaimer _claimer;
+
+public:
+ G1ParallelObjectIterator(uint thread_num) :
+ _heap(G1CollectedHeap::heap()),
+ _claimer(thread_num == 0 ? G1CollectedHeap::heap()->workers()->active_workers() : thread_num) {}
+
+ virtual void object_iterate(ObjectClosure* cl, uint worker_id) {
+ _heap->object_iterate_parallel(cl, worker_id, &_claimer);
+ }
+};
+
+ParallelObjectIterator* G1CollectedHeap::parallel_object_iterator(uint thread_num) {
+ return new G1ParallelObjectIterator(thread_num);
+}
+
+void G1CollectedHeap::object_iterate_parallel(ObjectClosure* cl, uint worker_id, HeapRegionClaimer* claimer) {
+ IterateObjectClosureRegionClosure blk(cl);
+ heap_region_par_iterate_from_worker_offset(&blk, claimer, worker_id);
+}
+
void G1CollectedHeap::keep_alive(oop obj) {
G1BarrierSet::enqueue(obj);
}
diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
index bb46cae83..82f59d69b 100644
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
@@ -1125,9 +1125,13 @@ public:
// Iteration functions.
+ void object_iterate_parallel(ObjectClosure* cl, uint worker_id, HeapRegionClaimer* claimer);
+
// Iterate over all objects, calling "cl.do_object" on each.
virtual void object_iterate(ObjectClosure* cl);
+ virtual ParallelObjectIterator* parallel_object_iterator(uint thread_num);
+
virtual void safe_object_iterate(ObjectClosure* cl) {
object_iterate(cl);
}
diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp
index 29f967fb3..66e1b32a6 100644
--- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp
+++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp
@@ -523,6 +523,70 @@ void ParallelScavengeHeap::object_iterate(ObjectClosure* cl) {
old_gen()->object_iterate(cl);
}
+// The HeapBlockClaimer is used during parallel iteration over the heap,
+// allowing workers to claim heap areas ("blocks"), gaining exclusive rights to these.
+// The eden and survivor spaces are treated as single blocks as it is hard to divide
+// these spaces.
+// The old space is divided into fixed-size blocks.
+class HeapBlockClaimer : public StackObj {
+ size_t _claimed_index;
+
+public:
+ static const size_t InvalidIndex = SIZE_MAX;
+ static const size_t EdenIndex = 0;
+ static const size_t SurvivorIndex = 1;
+ static const size_t NumNonOldGenClaims = 2;
+
+ HeapBlockClaimer() : _claimed_index(EdenIndex) { }
+ // Claim the block and get the block index.
+ size_t claim_and_get_block() {
+ size_t block_index;
+ block_index = Atomic::add(1u, &_claimed_index) - 1; // TODO: original impl is: Atomic::fetch_and_add(&_claimed_index, 1u);
+
+ PSOldGen* old_gen = ParallelScavengeHeap::heap()->old_gen();
+ size_t num_claims = old_gen->num_iterable_blocks() + NumNonOldGenClaims;
+
+ return block_index < num_claims ? block_index : InvalidIndex;
+ }
+};
+
+void ParallelScavengeHeap::object_iterate_parallel(ObjectClosure* cl,
+ HeapBlockClaimer* claimer) {
+ size_t block_index = claimer->claim_and_get_block();
+ // Iterate until all blocks are claimed
+ if (block_index == HeapBlockClaimer::EdenIndex) {
+ young_gen()->eden_space()->object_iterate(cl);
+ block_index = claimer->claim_and_get_block();
+ }
+ if (block_index == HeapBlockClaimer::SurvivorIndex) {
+ young_gen()->from_space()->object_iterate(cl);
+ young_gen()->to_space()->object_iterate(cl);
+ block_index = claimer->claim_and_get_block();
+ }
+ while (block_index != HeapBlockClaimer::InvalidIndex) {
+ old_gen()->object_iterate_block(cl, block_index - HeapBlockClaimer::NumNonOldGenClaims);
+ block_index = claimer->claim_and_get_block();
+ }
+}
+
+class PSScavengeParallelObjectIterator : public ParallelObjectIterator {
+private:
+ ParallelScavengeHeap* _heap;
+ HeapBlockClaimer _claimer;
+
+public:
+ PSScavengeParallelObjectIterator() :
+ _heap(ParallelScavengeHeap::heap()),
+ _claimer() {}
+
+ virtual void object_iterate(ObjectClosure* cl, uint worker_id) {
+ _heap->object_iterate_parallel(cl, &_claimer);
+ }
+};
+
+ParallelObjectIterator* ParallelScavengeHeap::parallel_object_iterator(uint thread_num) {
+ return new PSScavengeParallelObjectIterator();
+}
HeapWord* ParallelScavengeHeap::block_start(const void* addr) const {
if (young_gen()->is_in_reserved(addr)) {
diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp
index 5d18efb92..0a9b7bd3f 100644
--- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp
+++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp
@@ -44,6 +44,7 @@
class AdjoiningGenerations;
class GCHeapSummary;
class GCTaskManager;
+class HeapBlockClaimer;
class MemoryManager;
class MemoryPool;
class PSAdaptiveSizePolicy;
@@ -79,6 +80,8 @@ class ParallelScavengeHeap : public CollectedHeap {
MemoryPool* _survivor_pool;
MemoryPool* _old_pool;
+ WorkGang _workers;
+
virtual void initialize_serviceability();
void trace_heap(GCWhen::Type when, const GCTracer* tracer);
@@ -93,7 +96,20 @@ class ParallelScavengeHeap : public CollectedHeap {
public:
ParallelScavengeHeap(GenerationSizer* policy) :
- CollectedHeap(), _collector_policy(policy), _death_march_count(0) { }
+ CollectedHeap(),
+ _collector_policy(policy),
+ _death_march_count(0),
+ _young_manager(NULL),
+ _old_manager(NULL),
+ _eden_pool(NULL),
+ _survivor_pool(NULL),
+ _old_pool(NULL),
+ _workers("GC Thread",
+ ParallelGCThreads,
+ true /* are_GC_task_threads */,
+ false /* are_ConcurrentGC_threads */) {
+ _workers.initialize_workers();
+ }
// For use by VM operations
enum CollectionType {
@@ -217,6 +233,8 @@ class ParallelScavengeHeap : public CollectedHeap {
void object_iterate(ObjectClosure* cl);
void safe_object_iterate(ObjectClosure* cl) { object_iterate(cl); }
+ void object_iterate_parallel(ObjectClosure* cl, HeapBlockClaimer* claimer);
+ virtual ParallelObjectIterator* parallel_object_iterator(uint thread_num);
HeapWord* block_start(const void* addr) const;
size_t block_size(const HeapWord* addr) const;
@@ -232,6 +250,8 @@ class ParallelScavengeHeap : public CollectedHeap {
virtual void gc_threads_do(ThreadClosure* tc) const;
virtual void print_tracing_info() const;
+ virtual WorkGang* get_safepoint_workers() { return &_workers; }
+
void verify(VerifyOption option /* ignored */);
// Resize the young generation. The reserved space for the
diff --git a/src/hotspot/share/gc/parallel/psOldGen.cpp b/src/hotspot/share/gc/parallel/psOldGen.cpp
index 35844b14b..dbb5148fd 100644
--- a/src/hotspot/share/gc/parallel/psOldGen.cpp
+++ b/src/hotspot/share/gc/parallel/psOldGen.cpp
@@ -213,6 +213,38 @@ HeapWord* PSOldGen::allocate(size_t word_size) {
return res;
}
+size_t PSOldGen::num_iterable_blocks() const {
+ return (object_space()->used_in_bytes() + IterateBlockSize - 1) / IterateBlockSize;
+}
+
+void PSOldGen::object_iterate_block(ObjectClosure* cl, size_t block_index) {
+ size_t block_word_size = IterateBlockSize / HeapWordSize;
+ assert((block_word_size % (ObjectStartArray::block_size)) == 0,
+ "Block size not a multiple of start_array block");
+
+ MutableSpace *space = object_space();
+
+ HeapWord* begin = space->bottom() + block_index * block_word_size;
+ HeapWord* end = MIN2(space->top(), begin + block_word_size);
+
+ if (!start_array()->object_starts_in_range(begin, end)) {
+ return;
+ }
+
+ // Get object starting at or reaching into this block.
+ HeapWord* start = start_array()->object_start(begin);
+ if (start < begin) {
+ start += oop(start)->size();
+ }
+ assert(start >= begin,
+ "Object address" PTR_FORMAT " must be larger or equal to block address at " PTR_FORMAT,
+ p2i(start), p2i(begin));
+ // Iterate all objects until the end.
+ for (HeapWord* p = start; p < end; p += oop(p)->size()) {
+ cl->do_object(oop(p));
+ }
+}
+
HeapWord* PSOldGen::expand_and_allocate(size_t word_size) {
expand(word_size*HeapWordSize);
if (GCExpandToAllocateDelayMillis > 0) {
diff --git a/src/hotspot/share/gc/parallel/psOldGen.hpp b/src/hotspot/share/gc/parallel/psOldGen.hpp
index fa27f5a04..fa6e4849b 100644
--- a/src/hotspot/share/gc/parallel/psOldGen.hpp
+++ b/src/hotspot/share/gc/parallel/psOldGen.hpp
@@ -59,6 +59,9 @@ class PSOldGen : public CHeapObj<mtGC> {
const size_t _min_gen_size;
const size_t _max_gen_size;
+ // Block size for parallel iteration
+ static const size_t IterateBlockSize = 1024 * 1024;
+
// Used when initializing the _name field.
static inline const char* select_name();
@@ -195,6 +198,14 @@ class PSOldGen : public CHeapObj<mtGC> {
void oop_iterate(OopIterateClosure* cl) { object_space()->oop_iterate(cl); }
void object_iterate(ObjectClosure* cl) { object_space()->object_iterate(cl); }
+ // Number of blocks to be iterated over in the used part of old gen.
+ size_t num_iterable_blocks() const;
+ // Iterate the objects starting in block block_index within [bottom, top) of the
+ // old gen. The object just reaching into this block is not iterated over.
+ // A block is an evenly sized non-overlapping part of the old gen of
+ // IterateBlockSize bytes.
+ void object_iterate_block(ObjectClosure* cl, size_t block_index);
+
// Debugging - do not use for time critical operations
virtual void print() const;
virtual void print_on(outputStream* st) const;
diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp
index 47acf22cb..bcd4da29a 100644
--- a/src/hotspot/share/gc/shared/collectedHeap.hpp
+++ b/src/hotspot/share/gc/shared/collectedHeap.hpp
@@ -28,6 +28,7 @@
#include "gc/shared/gcCause.hpp"
#include "gc/shared/gcWhen.hpp"
#include "memory/allocation.hpp"
+#include "memory/heapInspection.hpp"
#include "runtime/handles.hpp"
#include "runtime/perfData.hpp"
#include "runtime/safepoint.hpp"
@@ -42,6 +43,7 @@
// class defines the functions that a heap must implement, and contains
// infrastructure common to all heaps.
+class AbstractGangTask;
class AdaptiveSizePolicy;
class BarrierSet;
class CollectorPolicy;
@@ -83,6 +85,11 @@ class GCHeapLog : public EventLogBase<GCMessage> {
}
};
+class ParallelObjectIterator : public CHeapObj<mtGC> {
+public:
+ virtual void object_iterate(ObjectClosure* cl, uint worker_id) = 0;
+};
+
//
// CollectedHeap
// GenCollectedHeap
@@ -434,6 +441,10 @@ 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) {
+ return NULL;
+ }
+
// Similar to object_iterate() except iterates only
// over live objects.
virtual void safe_object_iterate(ObjectClosure* cl) = 0;
diff --git a/src/hotspot/share/gc/shared/vmGCOperations.cpp b/src/hotspot/share/gc/shared/vmGCOperations.cpp
index b02305a6e..728290a7b 100644
--- a/src/hotspot/share/gc/shared/vmGCOperations.cpp
+++ b/src/hotspot/share/gc/shared/vmGCOperations.cpp
@@ -154,7 +154,7 @@ void VM_GC_HeapInspection::doit() {
}
HeapInspection inspect(_csv_format, _print_help, _print_class_stats,
_columns);
- inspect.heap_inspection(_out);
+ inspect.heap_inspection(_out, _parallel_thread_num);
}
diff --git a/src/hotspot/share/gc/shared/vmGCOperations.hpp b/src/hotspot/share/gc/shared/vmGCOperations.hpp
index 65876e559..ef73b45de 100644
--- a/src/hotspot/share/gc/shared/vmGCOperations.hpp
+++ b/src/hotspot/share/gc/shared/vmGCOperations.hpp
@@ -125,18 +125,21 @@ class VM_GC_HeapInspection: public VM_GC_Operation {
private:
outputStream* _out;
bool _full_gc;
+ uint _parallel_thread_num;
bool _csv_format; // "comma separated values" format for spreadsheet.
bool _print_help;
bool _print_class_stats;
const char* _columns;
public:
- VM_GC_HeapInspection(outputStream* out, bool request_full_gc) :
+ VM_GC_HeapInspection(outputStream* out, bool request_full_gc,
+ uint parallel_thread_num = 1) :
VM_GC_Operation(0 /* total collections, dummy, ignored */,
GCCause::_heap_inspection /* GC Cause */,
0 /* total full collections, dummy, ignored */,
request_full_gc) {
_out = out;
_full_gc = request_full_gc;
+ _parallel_thread_num = parallel_thread_num;
_csv_format = false;
_print_help = false;
_print_class_stats = false;
diff --git a/src/hotspot/share/gc/shared/workgroup.hpp b/src/hotspot/share/gc/shared/workgroup.hpp
index 8b46d3bc4..109649df0 100644
--- a/src/hotspot/share/gc/shared/workgroup.hpp
+++ b/src/hotspot/share/gc/shared/workgroup.hpp
@@ -228,6 +228,27 @@ protected:
virtual AbstractGangWorker* allocate_worker(uint which);
};
+// Temporarily try to set the number of active workers.
+// It's not guaranteed that it succeeds, and users need to
+// query the number of active workers.
+class WithUpdatedActiveWorkers : public StackObj {
+private:
+ AbstractWorkGang* const _gang;
+ const uint _old_active_workers;
+
+public:
+ WithUpdatedActiveWorkers(AbstractWorkGang* gang, uint requested_num_workers) :
+ _gang(gang),
+ _old_active_workers(gang->active_workers()) {
+ uint capped_num_workers = MIN2(requested_num_workers, gang->total_workers());
+ gang->update_active_workers(capped_num_workers);
+ }
+
+ ~WithUpdatedActiveWorkers() {
+ _gang->update_active_workers(_old_active_workers);
+ }
+};
+
// Several instances of this class run in parallel as workers for a gang.
class AbstractGangWorker: public WorkerThread {
public:
diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp
index 9c2cdc117..dbc0eb274 100644
--- a/src/hotspot/share/memory/heapInspection.cpp
+++ b/src/hotspot/share/memory/heapInspection.cpp
@@ -31,6 +31,7 @@
#include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp"
#include "oops/reflectionAccessorImplKlassHelper.hpp"
+#include "runtime/atomic.hpp"
#include "runtime/os.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/macros.hpp"
@@ -236,6 +237,41 @@ size_t KlassInfoTable::size_of_instances_in_words() const {
return _size_of_instances_in_words;
}
+// Return false if the entry could not be recorded on account
+// of running out of space required to create a new entry.
+bool KlassInfoTable::merge_entry(const KlassInfoEntry* cie) {
+ Klass* k = cie->klass();
+ KlassInfoEntry* elt = lookup(k);
+ // elt may be NULL if it's a new klass for which we
+ // could not allocate space for a new entry in the hashtable.
+ if (elt != NULL) {
+ elt->set_count(elt->count() + cie->count());
+ elt->set_words(elt->words() + cie->words());
+ _size_of_instances_in_words += cie->words();
+ return true;
+ }
+ return false;
+}
+
+class KlassInfoTableMergeClosure : public KlassInfoClosure {
+ private:
+ KlassInfoTable* _dest;
+ bool _success;
+ public:
+ KlassInfoTableMergeClosure(KlassInfoTable* table) : _dest(table), _success(true) {}
+ void do_cinfo(KlassInfoEntry* cie) {
+ _success &= _dest->merge_entry(cie);
+ }
+ bool success() { return _success; }
+};
+
+// merge from table
+bool KlassInfoTable::merge(KlassInfoTable* table) {
+ KlassInfoTableMergeClosure closure(this);
+ table->iterate(&closure);
+ return closure.success();
+}
+
int KlassInfoHisto::sort_helper(KlassInfoEntry** e1, KlassInfoEntry** e2) {
return (*e1)->compare(*e1,*e2);
}
@@ -687,7 +723,7 @@ class HistoClosure : public KlassInfoClosure {
class RecordInstanceClosure : public ObjectClosure {
private:
KlassInfoTable* _cit;
- size_t _missed_count;
+ uintx _missed_count;
BoolObjectClosure* _filter;
public:
RecordInstanceClosure(KlassInfoTable* cit, BoolObjectClosure* filter) :
@@ -701,7 +737,7 @@ class RecordInstanceClosure : public ObjectClosure {
}
}
- size_t missed_count() { return _missed_count; }
+ uintx missed_count() { return _missed_count; }
private:
bool should_visit(oop obj) {
@@ -709,15 +745,73 @@ class RecordInstanceClosure : public ObjectClosure {
}
};
-size_t HeapInspection::populate_table(KlassInfoTable* cit, BoolObjectClosure *filter) {
- ResourceMark rm;
+// Heap inspection for every worker.
+// When native OOM hanppens for KlassInfoTable, set _success to false.
+void ParHeapInspectTask::work(uint worker_id) {
+ uintx missed_count = 0;
+ bool merge_success = true;
+ if (!Atomic::load(&_success)) {
+ // other worker has failed on parallel iteration.
+ return;
+ }
+ KlassInfoTable cit(false);
+ if (cit.allocation_failed()) {
+ // fail to allocate memory, stop parallel mode
+ Atomic::store(false, &_success);
+ return;
+ }
+ RecordInstanceClosure ric(&cit, _filter);
+ _poi->object_iterate(&ric, worker_id);
+ missed_count = ric.missed_count();
+ {
+ MutexLocker x(&_mutex);
+ merge_success = _shared_cit->merge(&cit);
+ }
+ if (merge_success) {
+ Atomic::add(missed_count, &_missed_count);
+ } else {
+ Atomic::store(false, &_success);
+ }
+}
+
+size_t HeapInspection::populate_table(KlassInfoTable* cit, BoolObjectClosure *filter, uint parallel_thread_num) {
+ // Try parallel first.
+ if (parallel_thread_num > 1) {
+ ResourceMark rm;
+
+ WorkGang* gang = Universe::heap()->get_safepoint_workers();
+ if (gang != NULL) {
+ // The GC provided a WorkGang to be used during a safepoint.
+
+ // Can't run with more threads than provided by the WorkGang.
+ WithUpdatedActiveWorkers update_and_restore(gang, parallel_thread_num);
+
+ ParallelObjectIterator* poi = Universe::heap()->parallel_object_iterator(gang->active_workers());
+ if (poi != NULL) {
+ // The GC supports parallel object iteration.
+
+ ParHeapInspectTask task(poi, cit, filter);
+ // Run task with the active workers.
+
+ gang->run_task(&task);
+
+ delete poi;
+ if (task.success()) {
+ return task.missed_count();
+ }
+ }
+ }
+ }
+
+ ResourceMark rm;
+ // If no parallel iteration available, run serially.
RecordInstanceClosure ric(cit, filter);
Universe::heap()->safe_object_iterate(&ric);
return ric.missed_count();
}
-void HeapInspection::heap_inspection(outputStream* st) {
+void HeapInspection::heap_inspection(outputStream* st, uint parallel_thread_num) {
ResourceMark rm;
if (_print_help) {
@@ -741,9 +835,9 @@ void HeapInspection::heap_inspection(outputStream* st) {
KlassInfoTable cit(_print_class_stats);
if (!cit.allocation_failed()) {
// populate table with object allocation info
- size_t missed_count = populate_table(&cit);
+ uintx missed_count = populate_table(&cit, NULL, parallel_thread_num);
if (missed_count != 0) {
- st->print_cr("WARNING: Ran out of C-heap; undercounted " SIZE_FORMAT
+ st->print_cr("WARNING: Ran out of C-heap; undercounted " UINTX_FORMAT
" total instances in data below",
missed_count);
}
diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp
index d8935dc68..026293bf7 100644
--- a/src/hotspot/share/memory/heapInspection.hpp
+++ b/src/hotspot/share/memory/heapInspection.hpp
@@ -25,12 +25,15 @@
#ifndef SHARE_VM_MEMORY_HEAPINSPECTION_HPP
#define SHARE_VM_MEMORY_HEAPINSPECTION_HPP
+#include "gc/shared/workgroup.hpp"
#include "memory/allocation.hpp"
#include "oops/objArrayOop.hpp"
#include "oops/oop.hpp"
#include "oops/annotations.hpp"
#include "utilities/macros.hpp"
+class ParallelObjectIterator;
+
#if INCLUDE_SERVICES
@@ -261,6 +264,8 @@ class KlassInfoTable: public StackObj {
void iterate(KlassInfoClosure* cic);
bool allocation_failed() { return _buckets == NULL; }
size_t size_of_instances_in_words() const;
+ bool merge(KlassInfoTable* table);
+ bool merge_entry(const KlassInfoEntry* cie);
friend class KlassInfoHisto;
friend class KlassHierarchy;
@@ -364,11 +369,46 @@ class HeapInspection : public StackObj {
bool print_class_stats, const char *columns) :
_csv_format(csv_format), _print_help(print_help),
_print_class_stats(print_class_stats), _columns(columns) {}
- void heap_inspection(outputStream* st) NOT_SERVICES_RETURN;
- size_t populate_table(KlassInfoTable* cit, BoolObjectClosure* filter = NULL) NOT_SERVICES_RETURN_(0);
+ void heap_inspection(outputStream* st, uint parallel_thread_num = 1) NOT_SERVICES_RETURN;
+ size_t populate_table(KlassInfoTable* cit, BoolObjectClosure* filter = NULL, uint parallel_thread_num = 1) NOT_SERVICES_RETURN_(0);
static void find_instances_at_safepoint(Klass* k, GrowableArray<oop>* result) NOT_SERVICES_RETURN;
private:
void iterate_over_heap(KlassInfoTable* cit, BoolObjectClosure* filter = NULL);
};
+// Parallel heap inspection task. Parallel inspection can fail due to
+// a native OOM when allocating memory for TL-KlassInfoTable.
+// _success will be set false on an OOM, and serial inspection tried.
+class ParHeapInspectTask : public AbstractGangTask {
+private:
+ ParallelObjectIterator *_poi;
+ KlassInfoTable *_shared_cit;
+ BoolObjectClosure *_filter;
+ uintx _missed_count;
+ bool _success;
+ Mutex _mutex;
+
+public:
+ ParHeapInspectTask(ParallelObjectIterator *poi,
+ KlassInfoTable *shared_cit,
+ BoolObjectClosure *filter) :
+ AbstractGangTask("Iterating heap"),
+ _poi(poi),
+ _shared_cit(shared_cit),
+ _filter(filter),
+ _missed_count(0),
+ _success(true),
+ _mutex(Mutex::leaf, "Parallel heap iteration data merge lock") {}
+
+ uintx missed_count() const {
+ return _missed_count;
+ }
+
+ bool success() {
+ return _success;
+ }
+
+ virtual void work(uint worker_id);
+};
+
#endif // SHARE_VM_MEMORY_HEAPINSPECTION_HPP
diff --git a/src/hotspot/share/runtime/arguments.hpp b/src/hotspot/share/runtime/arguments.hpp
index bd439aab0..9827a4c66 100644
--- a/src/hotspot/share/runtime/arguments.hpp
+++ b/src/hotspot/share/runtime/arguments.hpp
@@ -450,12 +450,6 @@ class Arguments : AllStatic {
static ArgsRange check_memory_size(julong size, julong min_size, julong max_size);
static ArgsRange parse_memory_size(const char* s, julong* long_arg,
julong min_size, julong max_size = max_uintx);
- // Parse a string for a unsigned integer. Returns true if value
- // is an unsigned integer greater than or equal to the minimum
- // parameter passed and returns the value in uintx_arg. Returns
- // false otherwise, with uintx_arg undefined.
- static bool parse_uintx(const char* value, uintx* uintx_arg,
- uintx min_size);
// methods to build strings from individual args
static void build_jvm_args(const char* arg);
@@ -493,6 +487,12 @@ class Arguments : AllStatic {
public:
// Parses the arguments, first phase
static jint parse(const JavaVMInitArgs* args);
+ // Parse a string for a unsigned integer. Returns true if value
+ // is an unsigned integer greater than or equal to the minimum
+ // parameter passed and returns the value in uintx_arg. Returns
+ // false otherwise, with uintx_arg undefined.
+ static bool parse_uintx(const char* value, uintx* uintx_arg,
+ uintx min_size);
// Apply ergonomics
static jint apply_ergo();
// Adjusts the arguments after the OS have adjusted the arguments
diff --git a/src/hotspot/share/services/attachListener.cpp b/src/hotspot/share/services/attachListener.cpp
index fc77970a0..b0f3b2e87 100644
--- a/src/hotspot/share/services/attachListener.cpp
+++ b/src/hotspot/share/services/attachListener.cpp
@@ -258,9 +258,11 @@ jint dump_heap(AttachOperation* op, outputStream* out) {
//
// Input arguments :-
// arg0: "-live" or "-all"
+// arg1: parallel thread number
static jint heap_inspection(AttachOperation* op, outputStream* out) {
bool live_objects_only = true; // default is true to retain the behavior before this change is made
const char* arg0 = op->arg(0);
+ uint parallel_thread_num = MAX2<uint>(1, (uint)os::initial_active_processor_count() * 3 / 8);
if (arg0 != NULL && (strlen(arg0) > 0)) {
if (strcmp(arg0, "-all") != 0 && strcmp(arg0, "-live") != 0) {
out->print_cr("Invalid argument to inspectheap operation: %s", arg0);
@@ -268,7 +270,18 @@ static jint heap_inspection(AttachOperation* op, outputStream* out) {
}
live_objects_only = strcmp(arg0, "-live") == 0;
}
- VM_GC_HeapInspection heapop(out, live_objects_only /* request full gc */);
+
+ const char* num_str = op->arg(1);
+ if (num_str != NULL && num_str[0] != '\0') {
+ uintx num;
+ if (!Arguments::parse_uintx(num_str, &num, 0)) {
+ out->print_cr("Invalid parallel thread number: [%s]", num_str);
+ return JNI_ERR;
+ }
+ parallel_thread_num = num == 0 ? parallel_thread_num : (uint)num;
+ }
+
+ VM_GC_HeapInspection heapop(out, live_objects_only /* request full gc */, parallel_thread_num);
VMThread::execute(&heapop);
return JNI_OK;
}
diff --git a/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java b/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java
index f2db61ab7..9af74f362 100644
--- a/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java
+++ b/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java
@@ -149,18 +149,28 @@ public class JMap {
throws AttachNotSupportedException, IOException,
UnsupportedEncodingException {
String liveopt = "-all";
- if (options.equals("") || options.equals("all")) {
- // pass
- }
- else if (options.equals("live")) {
- liveopt = "-live";
- }
- else {
- usage(1);
+ String parallel = null;
+ String subopts[] = options.split(",");
+
+ for (int i = 0; i < subopts.length; i++) {
+ String subopt = subopts[i];
+ if (subopt.equals("") || subopt.equals("all")) {
+ // pass
+ } else if (subopt.equals("live")) {
+ liveopt = "-live";
+ } else if (subopt.startsWith("parallel=")) {
+ parallel = subopt.substring("parallel=".length());
+ if (parallel == null) {
+ System.err.println("Fail: no number provided in option: '" + subopt + "'");
+ System.exit(1);
+ }
+ } else {
+ usage(1);
+ }
}
// inspectHeap is not the same as jcmd GC.class_histogram
- executeCommandForPid(pid, "inspectheap", liveopt);
+ executeCommandForPid(pid, "inspectheap", liveopt, parallel);
}
private static void dump(String pid, String options)
@@ -246,9 +256,8 @@ public class JMap {
System.err.println(" to connect to running process and print class loader statistics");
System.err.println(" jmap -finalizerinfo <pid>");
System.err.println(" to connect to running process and print information on objects awaiting finalization");
- System.err.println(" jmap -histo[:live] <pid>");
+ System.err.println(" jmap -histo:<histo-options> <pid>");
System.err.println(" to connect to running process and print histogram of java object heap");
- System.err.println(" if the \"live\" suboption is specified, only count live objects");
System.err.println(" jmap -dump:<dump-options> <pid>");
System.err.println(" to connect to running process and dump java heap");
System.err.println(" jmap -? -h --help");
@@ -261,6 +270,16 @@ public class JMap {
System.err.println(" file=<file> dump heap to <file>");
System.err.println("");
System.err.println(" Example: jmap -dump:live,format=b,file=heap.bin <pid>");
+ System.err.println("");
+ System.err.println(" histo-options:");
+ System.err.println(" live count only live objects");
+ System.err.println(" all count all objects in the heap (default if one of \"live\" or \"all\" is not specified)");
+ System.err.println(" parallel=<number> parallel threads number for heap iteration:");
+ System.err.println(" parallel=0 default behavior, use predefined number of threads");
+ System.err.println(" parallel=1 disable parallel heap iteration");
+ System.err.println(" parallel=<N> use N threads for parallel heap iteration");
+ System.err.println("");
+ System.err.println(" Example: jmap -histo:live,parallel=2 <pid>");
System.exit(exit);
}
}
diff --git a/test/jdk/sun/tools/jmap/BasicJMapTest.java b/test/jdk/sun/tools/jmap/BasicJMapTest.java
index c0432dede..960705e24 100644
--- a/test/jdk/sun/tools/jmap/BasicJMapTest.java
+++ b/test/jdk/sun/tools/jmap/BasicJMapTest.java
@@ -45,6 +45,35 @@ import jdk.testlibrary.ProcessTools;
* @build jdk.test.lib.hprof.util.*
* @run main/timeout=240 BasicJMapTest
*/
+
+/*
+ * @test id=Parallel
+ * @summary Unit test for jmap utility (Parallel GC)
+ * @key intermittent
+ * @library /lib/testlibrary
+ * @library /test/lib
+ * @build jdk.testlibrary.*
+ * @build jdk.test.lib.hprof.*
+ * @build jdk.test.lib.hprof.model.*
+ * @build jdk.test.lib.hprof.parser.*
+ * @build jdk.test.lib.hprof.util.*
+ * @run main/othervm/timeout=240 -XX:+UseParallelGC BasicJMapTest
+ */
+
+/*
+ * @test id=G1
+ * @summary Unit test for jmap utility (G1 GC)
+ * @key intermittent
+ * @library /lib/testlibrary
+ * @library /test/lib
+ * @build jdk.testlibrary.*
+ * @build jdk.test.lib.hprof.*
+ * @build jdk.test.lib.hprof.model.*
+ * @build jdk.test.lib.hprof.parser.*
+ * @build jdk.test.lib.hprof.util.*
+ * @run main/othervm/timeout=240 -XX:+UseG1GC BasicJMapTest
+ */
+
public class BasicJMapTest {
private static ProcessBuilder processBuilder = new ProcessBuilder();
@@ -68,6 +97,32 @@ public class BasicJMapTest {
output.shouldHaveExitValue(0);
}
+ private static void testHistoParallelZero() throws Exception {
+ OutputAnalyzer output = jmap("-histo:parallel=0");
+ output.shouldHaveExitValue(0);
+ }
+
+ private static void testHistoParallel() throws Exception {
+ OutputAnalyzer output = jmap("-histo:parallel=2");
+ output.shouldHaveExitValue(0);
+ }
+
+ private static void testHistoNonParallel() throws Exception {
+ OutputAnalyzer output = jmap("-histo:parallel=1");
+ output.shouldHaveExitValue(0);
+ }
+
+ private static void testHistoMultipleParameters() throws Exception {
+ OutputAnalyzer output = jmap("-histo:parallel=2,live");
+ output.shouldHaveExitValue(0);
+ output = jmap("-histo:live,parallel=2");
+ output.shouldHaveExitValue(0);
+ output = jmap("-histo:parallel=2,all");
+ output.shouldHaveExitValue(0);
+ output = jmap("-histo:all,parallel=2");
+ output.shouldHaveExitValue(0);
+ }
+
private static void testFinalizerInfo() throws Exception {
OutputAnalyzer output = jmap("-finalizerinfo");
output.shouldHaveExitValue(0);
--
2.19.0
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C++
1
https://gitee.com/anar/openjdk-11.git
git@gitee.com:anar/openjdk-11.git
anar
openjdk-11
openjdk-11
master

搜索帮助