1 Star 0 Fork 82

starlet_dx/openjdk-1.8.0

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
8189688-NMT-Report-per-class-load-metadata-informati.patch 19.02 KB
一键复制 编辑 原始数据 按行查看 历史
eapen 提交于 2023-01-11 10:00 . I69W1Y: Add feature and bug fix for 8u352
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
From 528a3b6459e34532120f468ba9afb8833d516f5a Mon Sep 17 00:00:00 2001
From: eapen <zhangyipeng7@huawei.com>
Date: Thu, 15 Dec 2022 11:38:55 +0800
Subject: [PATCH 19/33] I68TO2: 8189688: NMT: Report per-class load metadata
information
---
hotspot/src/share/vm/memory/metaspace.cpp | 322 ++++++++++++++++++++++++-
hotspot/src/share/vm/memory/metaspace.hpp | 4 +
hotspot/src/share/vm/runtime/vm_operations.cpp | 4 +
hotspot/src/share/vm/runtime/vm_operations.hpp | 12 +
hotspot/src/share/vm/services/nmtDCmd.cpp | 16 +-
hotspot/src/share/vm/services/nmtDCmd.hpp | 1 +
6 files changed, 354 insertions(+), 5 deletions(-)
diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp
index 6c4654b..cf4a112 100644
--- a/hotspot/src/share/vm/memory/metaspace.cpp
+++ b/hotspot/src/share/vm/memory/metaspace.cpp
@@ -75,6 +75,22 @@ enum ChunkIndex {
NumberOfInUseLists = 4
};
+// Helper, returns a descriptive name for the given index.
+static const char* chunk_size_name(ChunkIndex index) {
+ switch (index) {
+ case SpecializedIndex:
+ return "specialized";
+ case SmallIndex:
+ return "small";
+ case MediumIndex:
+ return "medium";
+ case HumongousIndex:
+ return "humongous";
+ default:
+ return "Invalid index";
+ }
+}
+
enum ChunkSizes { // in words.
ClassSpecializedChunk = 128,
SpecializedChunk = 128,
@@ -89,6 +105,18 @@ static ChunkIndex next_chunk_index(ChunkIndex i) {
return (ChunkIndex) (i+1);
}
+static const char* scale_unit(size_t scale) {
+ switch(scale) {
+ case 1: return "BYTES";
+ case K: return "KB";
+ case M: return "MB";
+ case G: return "GB";
+ default:
+ ShouldNotReachHere();
+ return NULL;
+ }
+}
+
volatile intptr_t MetaspaceGC::_capacity_until_GC = 0;
uint MetaspaceGC::_shrink_factor = 0;
bool MetaspaceGC::_should_concurrent_collect = false;
@@ -141,6 +169,18 @@ class ChunkManager : public CHeapObj<mtInternal> {
}
void verify_free_chunks_count();
+ struct ChunkManagerStatistics {
+ size_t num_by_type[NumberOfFreeLists];
+ size_t single_size_by_type[NumberOfFreeLists];
+ size_t total_size_by_type[NumberOfFreeLists];
+ size_t num_humongous_chunks;
+ size_t total_size_humongous_chunks;
+ };
+
+ void locked_get_statistics(ChunkManagerStatistics* stat) const;
+ void get_statistics(ChunkManagerStatistics* stat) const;
+ static void print_statistics(const ChunkManagerStatistics* stat, outputStream* out, size_t scale);
+
public:
ChunkManager(size_t specialized_size, size_t small_size, size_t medium_size)
@@ -157,6 +197,9 @@ class ChunkManager : public CHeapObj<mtInternal> {
// for special, small, medium, and humongous chunks.
ChunkIndex list_index(size_t size);
+ // Map a given index to the chunk size.
+ size_t size_by_index(ChunkIndex index) const;
+
// Remove the chunk from its freelist. It is
// expected to be on one of the _free_chunks[] lists.
void remove_chunk(Metachunk* chunk);
@@ -249,6 +292,10 @@ class ChunkManager : public CHeapObj<mtInternal> {
void locked_print_sum_free_chunks(outputStream* st);
void print_on(outputStream* st) const;
+
+ // Prints composition for both non-class and (if available)
+ // class chunk manager.
+ static void print_all_chunkmanagers(outputStream* out, size_t scale = 1);
};
// Used to manage the free list of Metablocks (a block corresponds
@@ -1707,7 +1754,6 @@ bool Metadebug::test_metadata_failure() {
#endif
// ChunkManager methods
-
size_t ChunkManager::free_chunks_total_words() {
return _free_chunks_total;
}
@@ -1729,6 +1775,12 @@ size_t ChunkManager::free_chunks_count() {
return _free_chunks_count;
}
+size_t ChunkManager::size_by_index(ChunkIndex index) const {
+ index_bounds_check(index);
+ assert(index != HumongousIndex, "Do not call for humongous chunks.");
+ return _free_chunks[index].size();
+}
+
void ChunkManager::locked_verify_free_chunks_total() {
assert_lock_strong(SpaceManager::expand_lock());
assert(sum_free_chunks() == _free_chunks_total,
@@ -1918,7 +1970,83 @@ Metachunk* ChunkManager::chunk_freelist_allocate(size_t word_size) {
void ChunkManager::print_on(outputStream* out) const {
if (PrintFLSStatistics != 0) {
- const_cast<ChunkManager *>(this)->humongous_dictionary()->report_statistics();
+ _humongous_dictionary.report_statistics();
+ }
+}
+
+void ChunkManager::locked_get_statistics(ChunkManagerStatistics* stat) const {
+ assert_lock_strong(SpaceManager::expand_lock());
+ for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) {
+ stat->num_by_type[i] = num_free_chunks(i);
+ stat->single_size_by_type[i] = size_by_index(i);
+ stat->total_size_by_type[i] = size_free_chunks_in_bytes(i);
+ }
+ stat->num_humongous_chunks = num_free_chunks(HumongousIndex);
+ stat->total_size_humongous_chunks = size_free_chunks_in_bytes(HumongousIndex);
+}
+
+void ChunkManager::get_statistics(ChunkManagerStatistics* stat) const {
+ MutexLockerEx cl(SpaceManager::expand_lock(),
+ Mutex::_no_safepoint_check_flag);
+ locked_get_statistics(stat);
+}
+
+void ChunkManager::print_statistics(const ChunkManagerStatistics* stat, outputStream* out, size_t scale) {
+ size_t total = 0;
+ assert(scale == 1 || scale == K || scale == M || scale == G, "Invalid scale");
+
+ const char* unit = scale_unit(scale);
+ for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) {
+ out->print(" " SIZE_FORMAT " %s (" SIZE_FORMAT " bytes) chunks, total ",
+ stat->num_by_type[i], chunk_size_name(i),
+ stat->single_size_by_type[i]);
+ if (scale == 1) {
+ out->print_cr(SIZE_FORMAT " bytes", stat->total_size_by_type[i]);
+ } else {
+ out->print_cr("%.2f%s", (float)stat->total_size_by_type[i] / scale, unit);
+ }
+
+ total += stat->total_size_by_type[i];
+ }
+
+ total += stat->total_size_humongous_chunks;
+
+ if (scale == 1) {
+ out->print_cr(" " SIZE_FORMAT " humongous chunks, total " SIZE_FORMAT " bytes",
+ stat->num_humongous_chunks, stat->total_size_humongous_chunks);
+
+ out->print_cr(" total size: " SIZE_FORMAT " bytes.", total);
+ } else {
+ out->print_cr(" " SIZE_FORMAT " humongous chunks, total %.2f%s",
+ stat->num_humongous_chunks,
+ (float)stat->total_size_humongous_chunks / scale, unit);
+
+ out->print_cr(" total size: %.2f%s.", (float)total / scale, unit);
+ }
+
+}
+
+void ChunkManager::print_all_chunkmanagers(outputStream* out, size_t scale) {
+ assert(scale == 1 || scale == K || scale == M || scale == G, "Invalid scale");
+
+ // Note: keep lock protection only to retrieving statistics; keep printing
+ // out of lock protection
+ ChunkManagerStatistics stat;
+ out->print_cr("Chunkmanager (non-class):");
+ const ChunkManager* const non_class_cm = Metaspace::chunk_manager_metadata();
+ if (non_class_cm != NULL) {
+ non_class_cm->get_statistics(&stat);
+ ChunkManager::print_statistics(&stat, out, scale);
+ } else {
+ out->print_cr("unavailable.");
+ }
+ out->print_cr("Chunkmanager (class):");
+ const ChunkManager* const class_cm = Metaspace::chunk_manager_class();
+ if (class_cm != NULL) {
+ class_cm->get_statistics(&stat);
+ ChunkManager::print_statistics(&stat, out, scale);
+ } else {
+ out->print_cr("unavailable.");
}
}
@@ -2930,6 +3058,195 @@ void MetaspaceAux::print_waste(outputStream* out) {
}
}
+class MetadataStats VALUE_OBJ_CLASS_SPEC {
+private:
+ size_t _capacity;
+ size_t _used;
+ size_t _free;
+ size_t _waste;
+
+public:
+ MetadataStats() : _capacity(0), _used(0), _free(0), _waste(0) { }
+ MetadataStats(size_t capacity, size_t used, size_t free, size_t waste)
+ : _capacity(capacity), _used(used), _free(free), _waste(waste) { }
+
+ void add(const MetadataStats& stats) {
+ _capacity += stats.capacity();
+ _used += stats.used();
+ _free += stats.free();
+ _waste += stats.waste();
+ }
+
+ size_t capacity() const { return _capacity; }
+ size_t used() const { return _used; }
+ size_t free() const { return _free; }
+ size_t waste() const { return _waste; }
+
+ void print_on(outputStream* out, size_t scale) const;
+};
+
+
+void MetadataStats::print_on(outputStream* out, size_t scale) const {
+ const char* unit = scale_unit(scale);
+ out->print_cr("capacity=%10.2f%s used=%10.2f%s free=%10.2f%s waste=%10.2f%s",
+ (float)capacity() / scale, unit,
+ (float)used() / scale, unit,
+ (float)free() / scale, unit,
+ (float)waste() / scale, unit);
+}
+
+class PrintCLDMetaspaceInfoClosure : public CLDClosure {
+private:
+ outputStream* _out;
+ size_t _scale;
+
+ size_t _total_count;
+ MetadataStats _total_metadata;
+ MetadataStats _total_class;
+
+ size_t _total_anon_count;
+ MetadataStats _total_anon_metadata;
+ MetadataStats _total_anon_class;
+
+public:
+ PrintCLDMetaspaceInfoClosure(outputStream* out, size_t scale = K)
+ : _out(out), _scale(scale), _total_count(0), _total_anon_count(0) { }
+
+ ~PrintCLDMetaspaceInfoClosure() {
+ print_summary();
+ }
+
+ void do_cld(ClassLoaderData* cld) {
+ assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
+
+ if (cld->is_unloading()) return;
+ Metaspace* msp = cld->metaspace_or_null();
+ if (msp == NULL) {
+ return;
+ }
+
+ bool anonymous = false;
+ if (cld->is_anonymous()) {
+ _out->print_cr("ClassLoader: for anonymous class");
+ anonymous = true;
+ } else {
+ ResourceMark rm;
+ _out->print_cr("ClassLoader: %s", cld->loader_name());
+ }
+
+ print_metaspace(msp, anonymous);
+ _out->cr();
+ }
+
+private:
+ void print_metaspace(Metaspace* msp, bool anonymous);
+ void print_summary() const;
+};
+
+void PrintCLDMetaspaceInfoClosure::print_metaspace(Metaspace* msp, bool anonymous){
+ assert(msp != NULL, "Sanity");
+ SpaceManager* vsm = msp->vsm();
+ const char* unit = scale_unit(_scale);
+
+ size_t capacity = vsm->sum_capacity_in_chunks_in_use() * BytesPerWord;
+ size_t used = vsm->sum_used_in_chunks_in_use() * BytesPerWord;
+ size_t free = vsm->sum_free_in_chunks_in_use() * BytesPerWord;
+ size_t waste = vsm->sum_waste_in_chunks_in_use() * BytesPerWord;
+
+ _total_count ++;
+ MetadataStats metadata_stats(capacity, used, free, waste);
+ _total_metadata.add(metadata_stats);
+
+ if (anonymous) {
+ _total_anon_count ++;
+ _total_anon_metadata.add(metadata_stats);
+ }
+
+ _out->print(" Metadata ");
+ metadata_stats.print_on(_out, _scale);
+
+ if (Metaspace::using_class_space()) {
+ vsm = msp->class_vsm();
+
+ capacity = vsm->sum_capacity_in_chunks_in_use() * BytesPerWord;
+ used = vsm->sum_used_in_chunks_in_use() * BytesPerWord;
+ free = vsm->sum_free_in_chunks_in_use() * BytesPerWord;
+ waste = vsm->sum_waste_in_chunks_in_use() * BytesPerWord;
+
+ MetadataStats class_stats(capacity, used, free, waste);
+ _total_class.add(class_stats);
+
+ if (anonymous) {
+ _total_anon_class.add(class_stats);
+ }
+
+ _out->print(" Class data ");
+ class_stats.print_on(_out, _scale);
+ }
+}
+
+void PrintCLDMetaspaceInfoClosure::print_summary() const {
+ const char* unit = scale_unit(_scale);
+ _out->cr();
+ _out->print_cr("Summary:");
+
+ MetadataStats total;
+ total.add(_total_metadata);
+ total.add(_total_class);
+
+ _out->print(" Total class loaders=" SIZE_FORMAT_W(6) " ", _total_count);
+ total.print_on(_out, _scale);
+
+ _out->print(" Metadata ");
+ _total_metadata.print_on(_out, _scale);
+
+ if (Metaspace::using_class_space()) {
+ _out->print(" Class data ");
+ _total_class.print_on(_out, _scale);
+ }
+ _out->cr();
+
+ MetadataStats total_anon;
+ total_anon.add(_total_anon_metadata);
+ total_anon.add(_total_anon_class);
+
+ _out->print("For anonymous classes=" SIZE_FORMAT_W(6) " ", _total_anon_count);
+ total_anon.print_on(_out, _scale);
+
+ _out->print(" Metadata ");
+ _total_anon_metadata.print_on(_out, _scale);
+
+ if (Metaspace::using_class_space()) {
+ _out->print(" Class data ");
+ _total_anon_class.print_on(_out, _scale);
+ }
+}
+
+void MetaspaceAux::print_metadata_for_nmt(outputStream* out, size_t scale) {
+ const char* unit = scale_unit(scale);
+ out->print_cr("Metaspaces:");
+ out->print_cr(" Metadata space: reserved=" SIZE_FORMAT_W(10) "%s committed=" SIZE_FORMAT_W(10) "%s",
+ reserved_bytes(Metaspace::NonClassType) / scale, unit,
+ committed_bytes(Metaspace::NonClassType) / scale, unit);
+ if (Metaspace::using_class_space()) {
+ out->print_cr(" Class space: reserved=" SIZE_FORMAT_W(10) "%s committed=" SIZE_FORMAT_W(10) "%s",
+ reserved_bytes(Metaspace::ClassType) / scale, unit,
+ committed_bytes(Metaspace::ClassType) / scale, unit);
+ }
+
+ out->cr();
+ ChunkManager::print_all_chunkmanagers(out, scale);
+
+ out->cr();
+ out->print_cr("Per-classloader metadata:");
+ out->cr();
+
+ PrintCLDMetaspaceInfoClosure cl(out, scale);
+ ClassLoaderDataGraph::cld_do(&cl);
+}
+
+
+
// Dump global metaspace things from the end of ClassLoaderDataGraph
void MetaspaceAux::dump(outputStream* out) {
out->print_cr("All Metaspace:");
@@ -3743,6 +4060,7 @@ void Metaspace::report_metadata_oome(ClassLoaderData* loader_data, size_t word_s
loader_data->dump(gclog_or_tty);
}
MetaspaceAux::dump(gclog_or_tty);
+ ChunkManager::print_all_chunkmanagers(gclog_or_tty);
}
bool out_of_compressed_class_space = false;
diff --git a/hotspot/src/share/vm/memory/metaspace.hpp b/hotspot/src/share/vm/memory/metaspace.hpp
index 122dd4b..ff1b232 100644
--- a/hotspot/src/share/vm/memory/metaspace.hpp
+++ b/hotspot/src/share/vm/memory/metaspace.hpp
@@ -65,6 +65,7 @@ class MetaspaceTracer;
class MetaWord;
class Mutex;
class outputStream;
+class PrintCLDMetaspaceInfoClosure;
class SpaceManager;
class VirtualSpaceList;
@@ -88,6 +89,7 @@ class Metaspace : public CHeapObj<mtClass> {
friend class VM_CollectForMetadataAllocation;
friend class MetaspaceGC;
friend class MetaspaceAux;
+ friend class PrintCLDMetaspaceInfoClosure;
public:
enum MetadataType {
@@ -372,6 +374,8 @@ class MetaspaceAux : AllStatic {
return min_chunk_size_words() * BytesPerWord;
}
+ static void print_metadata_for_nmt(outputStream* out, size_t scale = K);
+
static bool has_chunk_free_list(Metaspace::MetadataType mdtype);
static MetaspaceChunkFreeListSummary chunk_free_list_summary(Metaspace::MetadataType mdtype);
diff --git a/hotspot/src/share/vm/runtime/vm_operations.cpp b/hotspot/src/share/vm/runtime/vm_operations.cpp
index d401ea6..b42d18f 100644
--- a/hotspot/src/share/vm/runtime/vm_operations.cpp
+++ b/hotspot/src/share/vm/runtime/vm_operations.cpp
@@ -209,6 +209,10 @@ void VM_PrintJNI::doit() {
JNIHandles::print_on(_out);
}
+void VM_PrintMetadata::doit() {
+ MetaspaceAux::print_metadata_for_nmt(_out, _scale);
+}
+
VM_FindDeadlocks::~VM_FindDeadlocks() {
if (_deadlocks != NULL) {
DeadlockCycle* cycle = _deadlocks;
diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp
index 3744040..19c33f8 100644
--- a/hotspot/src/share/vm/runtime/vm_operations.hpp
+++ b/hotspot/src/share/vm/runtime/vm_operations.hpp
@@ -101,6 +101,7 @@
template(ClassLoaderHierarchyOperation) \
template(JFROldObject) \
template(PrintClasses) \
+ template(PrintMetadata) \
class VM_Operation: public CHeapObj<mtInternal> {
public:
@@ -329,6 +330,17 @@ class VM_PrintJNI: public VM_Operation {
void doit();
};
+class VM_PrintMetadata : public VM_Operation {
+ private:
+ outputStream* _out;
+ size_t _scale;
+ public:
+ VM_PrintMetadata(outputStream* out, size_t scale) : _out(out), _scale(scale) {};
+
+ VMOp_Type type() const { return VMOp_PrintMetadata; }
+ void doit();
+};
+
class DeadlockCycle;
class VM_FindDeadlocks: public VM_Operation {
private:
diff --git a/hotspot/src/share/vm/services/nmtDCmd.cpp b/hotspot/src/share/vm/services/nmtDCmd.cpp
index fcad784..659ca33 100644
--- a/hotspot/src/share/vm/services/nmtDCmd.cpp
+++ b/hotspot/src/share/vm/services/nmtDCmd.cpp
@@ -24,6 +24,8 @@
#include "precompiled.hpp"
#include "runtime/mutexLocker.hpp"
+#include "runtime/vmThread.hpp"
+#include "runtime/vm_operations.hpp"
#include "services/nmtDCmd.hpp"
#include "services/memReporter.hpp"
#include "services/memTracker.hpp"
@@ -38,6 +40,8 @@ NMTDCmd::NMTDCmd(outputStream* output,
_detail("detail", "request runtime to report memory allocation >= "
"1K by each callsite.",
"BOOLEAN", false, "false"),
+ _metadata("metadata", "request runtime to report metadata information",
+ "BOOLEAN", false, "false"),
_baseline("baseline", "request runtime to baseline current memory usage, " \
"so it can be compared against in later time.",
"BOOLEAN", false, "false"),
@@ -57,6 +61,7 @@ NMTDCmd::NMTDCmd(outputStream* output,
"STRING", false, "KB") {
_dcmdparser.add_dcmd_option(&_summary);
_dcmdparser.add_dcmd_option(&_detail);
+ _dcmdparser.add_dcmd_option(&_metadata);
_dcmdparser.add_dcmd_option(&_baseline);
_dcmdparser.add_dcmd_option(&_summary_diff);
_dcmdparser.add_dcmd_option(&_detail_diff);
@@ -92,6 +97,7 @@ void NMTDCmd::execute(DCmdSource source, TRAPS) {
int nopt = 0;
if (_summary.is_set() && _summary.value()) { ++nopt; }
if (_detail.is_set() && _detail.value()) { ++nopt; }
+ if (_metadata.is_set() && _metadata.value()) { ++nopt; }
if (_baseline.is_set() && _baseline.value()) { ++nopt; }
if (_summary_diff.is_set() && _summary_diff.value()) { ++nopt; }
if (_detail_diff.is_set() && _detail_diff.value()) { ++nopt; }
@@ -100,7 +106,7 @@ void NMTDCmd::execute(DCmdSource source, TRAPS) {
if (nopt > 1) {
output()->print_cr("At most one of the following option can be specified: " \
- "summary, detail, baseline, summary.diff, detail.diff, shutdown");
+ "summary, detail, metadata, baseline, summary.diff, detail.diff, shutdown");
return;
} else if (nopt == 0) {
if (_summary.is_set()) {
@@ -118,9 +124,13 @@ void NMTDCmd::execute(DCmdSource source, TRAPS) {
report(true, scale_unit);
} else if (_detail.value()) {
if (!check_detail_tracking_level(output())) {
- return;
- }
+ return;
+ }
report(false, scale_unit);
+ } else if (_metadata.value()) {
+ size_t scale = get_scale(_scale.value());
+ VM_PrintMetadata op(output(), scale);
+ VMThread::execute(&op);
} else if (_baseline.value()) {
MemBaseline& baseline = MemTracker::get_baseline();
if (!baseline.baseline(MemTracker::tracking_level() != NMT_detail)) {
diff --git a/hotspot/src/share/vm/services/nmtDCmd.hpp b/hotspot/src/share/vm/services/nmtDCmd.hpp
index df1ab36..bbd1391 100644
--- a/hotspot/src/share/vm/services/nmtDCmd.hpp
+++ b/hotspot/src/share/vm/services/nmtDCmd.hpp
@@ -39,6 +39,7 @@ class NMTDCmd: public DCmdWithParser {
protected:
DCmdArgument<bool> _summary;
DCmdArgument<bool> _detail;
+ DCmdArgument<bool> _metadata;
DCmdArgument<bool> _baseline;
DCmdArgument<bool> _summary_diff;
DCmdArgument<bool> _detail_diff;
--
1.8.3.1
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/starlet-dx/openjdk-1.8.0.git
git@gitee.com:starlet-dx/openjdk-1.8.0.git
starlet-dx
openjdk-1.8.0
openjdk-1.8.0
master

搜索帮助