1 Star 0 Fork 74

DXwangg / openjdk-1.8.0

forked from src-openEuler / openjdk-1.8.0 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
8293114-GC-should-trim-the-native-heap-and-bug-fix.patch 57.16 KB
一键复制 编辑 原始数据 按行查看 历史
kuen 提交于 2023-01-28 14:19 . I6BBYW: upgrade to jdk8u362-ga
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503
From a5edc79220300bce7952feaacf28a832306884d8 Mon Sep 17 00:00:00 2001
From: eapen <zhangyipeng7@huawei.com>
Date: Mon, 12 Dec 2022 19:28:28 +0800
Subject: [PATCH 14/33] I68TO2: 8293114: GC should trim the native heap,8136854:G1 ConcurrentG1RefineThread::stop delays JVM shutdown for >150ms
---
hotspot/src/os/aix/vm/os_aix.cpp | 5 +
hotspot/src/os/bsd/vm/os_bsd.cpp | 5 +
hotspot/src/os/linux/vm/os_linux.cpp | 149 ++++++-
hotspot/src/os/linux/vm/os_linux.hpp | 57 ++-
hotspot/src/os/linux/vm/trimCHeapDCmd.cpp | 59 +--
hotspot/src/os/windows/vm/os_windows.cpp | 4 +
.../vm/gc_implementation/g1/g1CollectedHeap.cpp | 6 +
.../parallelScavenge/parallelScavengeHeap.cpp | 3 +
.../parallelScavenge/psParallelCompact.cpp | 6 +
.../shared/concurrentGCThread.cpp | 8 +-
.../shared/concurrentGCThread.hpp | 6 +-
.../gc_implementation/shared/gcTrimNativeHeap.cpp | 246 ++++++++++++
.../gc_implementation/shared/gcTrimNativeHeap.hpp | 66 ++++
hotspot/src/share/vm/memory/genCollectedHeap.cpp | 6 +
hotspot/src/share/vm/memory/sharedHeap.cpp | 6 +
hotspot/src/share/vm/runtime/globals.hpp | 10 +
hotspot/src/share/vm/runtime/init.cpp | 5 +-
hotspot/src/share/vm/runtime/java.cpp | 3 +
hotspot/src/share/vm/runtime/os.hpp | 11 +
.../src/share/vm/utilities/globalDefinitions.hpp | 3 +
hotspot/test/gc/TestTrimNative.java | 435 +++++++++++++++++++++
.../test/serviceability/dcmd/TrimLibcHeapTest.java | 7 +-
22 files changed, 994 insertions(+), 112 deletions(-)
create mode 100644 hotspot/src/share/vm/gc_implementation/shared/gcTrimNativeHeap.cpp
create mode 100644 hotspot/src/share/vm/gc_implementation/shared/gcTrimNativeHeap.hpp
create mode 100644 hotspot/test/gc/TestTrimNative.java
diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp
index b078bee..519b085 100644
--- a/hotspot/src/os/aix/vm/os_aix.cpp
+++ b/hotspot/src/os/aix/vm/os_aix.cpp
@@ -5266,3 +5266,8 @@ void TestReserveMemorySpecial_test() {
// No tests available for this platform
}
#endif
+
+// stubbed-out trim-native support
+bool os::can_trim_native_heap() { return false; }
+bool os::should_trim_native_heap() { return false; }
+bool os::trim_native_heap(os::size_change_t* rss_change) { return false; }
\ No newline at end of file
diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp
index 340334c..85e2861 100644
--- a/hotspot/src/os/bsd/vm/os_bsd.cpp
+++ b/hotspot/src/os/bsd/vm/os_bsd.cpp
@@ -4899,3 +4899,8 @@ void TestReserveMemorySpecial_test() {
// No tests available for this platform
}
#endif
+
+// stubbed-out trim-native support
+bool os::can_trim_native_heap() { return false; }
+bool os::should_trim_native_heap() { return false; }
+bool os::trim_native_heap(os::size_change_t* rss_change) { return false; }
\ No newline at end of file
diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp
index 099dafa..abf2031 100644
--- a/hotspot/src/os/linux/vm/os_linux.cpp
+++ b/hotspot/src/os/linux/vm/os_linux.cpp
@@ -153,8 +153,28 @@ const char * os::Linux::_libpthread_version = NULL;
pthread_condattr_t os::Linux::_condattr[1];
#ifdef __GLIBC__
-os::Linux::mallinfo_func_t os::Linux::_mallinfo = NULL;
-os::Linux::mallinfo2_func_t os::Linux::_mallinfo2 = NULL;
+// We want to be runnable with both old and new glibcs.
+// Old glibcs offer mallinfo(). New glibcs deprecate mallinfo() and offer mallinfo2()
+// as replacement. Future glibc's may remove the deprecated mallinfo().
+// Therefore we may have one, both, or possibly neither (?). Code should tolerate all
+// cases, which is why we resolve the functions dynamically. Outside code should use
+// the Linux::get_mallinfo() utility function which exists to hide this mess.
+struct glibc_mallinfo {
+ int arena;
+ int ordblks;
+ int smblks;
+ int hblks;
+ int hblkhd;
+ int usmblks;
+ int fsmblks;
+ int uordblks;
+ int fordblks;
+ int keepcost;
+};
+typedef struct glibc_mallinfo (*mallinfo_func_t)(void);
+typedef struct os::Linux::glibc_mallinfo2 (*mallinfo2_func_t)(void);
+static mallinfo_func_t g_mallinfo = NULL;
+static mallinfo2_func_t g_mallinfo2 = NULL;
#endif // __GLIBC__
static jlong initial_time_count=0;
@@ -2348,23 +2368,21 @@ void os::Linux::print_process_memory_info(outputStream* st) {
// Print glibc outstanding allocations.
// (note: there is no implementation of mallinfo for muslc)
#ifdef __GLIBC__
- size_t total_allocated = 0;
bool might_have_wrapped = false;
- if (_mallinfo2 != NULL) {
- struct glibc_mallinfo2 mi = _mallinfo2();
- total_allocated = mi.uordblks;
- } else if (_mallinfo != NULL) {
- // mallinfo is an old API. Member names mean next to nothing and, beyond that, are int.
- // So values may have wrapped around. Still useful enough to see how much glibc thinks
- // we allocated.
- struct glibc_mallinfo mi = _mallinfo();
- total_allocated = (size_t)(unsigned)mi.uordblks;
- // Since mallinfo members are int, glibc values may have wrapped. Warn about this.
- might_have_wrapped = (info.vmrss * K) > UINT_MAX && (info.vmrss * K) > (total_allocated + UINT_MAX);
- }
- if (_mallinfo2 != NULL || _mallinfo != NULL) {
- st->print_cr("C-Heap outstanding allocations: " SIZE_FORMAT "K%s",
- total_allocated / K,
+ glibc_mallinfo2 mi;
+ mallinfo_retval_t mirc = os::Linux::get_mallinfo(&mi);
+ if (mirc != os::Linux::error) {
+ size_t total_allocated = mi.uordblks + mi.hblkhd;
+ size_t free_retained = mi.fordblks;
+#ifdef _LP64
+ // If all we had is old mallinf(3), the values may have wrapped. Since that can confuse readers
+ // of this output, print a hint.
+ // We do this by checking virtual size of the process: if that is <4g, we could not have wrapped.
+ might_have_wrapped = (mirc == os::Linux::ok_but_possibly_wrapped) &&
+ ((info.vmsize * K) > UINT_MAX);
+#endif
+ st->print_cr("C-Heap outstanding allocations: " SIZE_FORMAT "K, retained: " SIZE_FORMAT "K%s",
+ total_allocated / K, free_retained / K,
might_have_wrapped ? " (may have wrapped)" : "");
}
@@ -5187,8 +5205,8 @@ void os::init(void) {
Linux::initialize_system_info();
#ifdef __GLIBC__
- Linux::_mallinfo = CAST_TO_FN_PTR(Linux::mallinfo_func_t, dlsym(RTLD_DEFAULT, "mallinfo"));
- Linux::_mallinfo2 = CAST_TO_FN_PTR(Linux::mallinfo2_func_t, dlsym(RTLD_DEFAULT, "mallinfo2"));
+ g_mallinfo = CAST_TO_FN_PTR(mallinfo_func_t, dlsym(RTLD_DEFAULT, "mallinfo"));
+ g_mallinfo2 = CAST_TO_FN_PTR(mallinfo2_func_t, dlsym(RTLD_DEFAULT, "mallinfo2"));
#endif // __GLIBC__
// _main_thread points to the thread that created/loaded the JVM.
@@ -6820,3 +6838,94 @@ void TestReserveMemorySpecial_test() {
}
#endif
+
+#ifdef __GLIBC__
+os::Linux::mallinfo_retval_t os::Linux::get_mallinfo(glibc_mallinfo2* out) {
+ if (g_mallinfo2) {
+ glibc_mallinfo2 mi = g_mallinfo2();
+ *out = mi;
+ return os::Linux::ok;
+ } else if (g_mallinfo) {
+ // mallinfo() returns 32-bit values. Not perfect but still useful if
+ // process virt size < 4g
+ glibc_mallinfo mi = g_mallinfo();
+ out->arena = (int) mi.arena;
+ out->ordblks = (int) mi.ordblks;
+ out->smblks = (int) mi.smblks;
+ out->hblks = (int) mi.hblks;
+ out->hblkhd = (int) mi.hblkhd;
+ out->usmblks = (int) mi.usmblks;
+ out->fsmblks = (int) mi.fsmblks;
+ out->uordblks = (int) mi.uordblks;
+ out->fordblks = (int) mi.fordblks;
+ out->keepcost = (int) mi.keepcost;
+ return os::Linux::ok_but_possibly_wrapped;
+ }
+ return os::Linux::ok;
+}
+#endif // __GLIBC__
+
+// Trim-native support
+bool os::can_trim_native_heap() {
+#ifdef __GLIBC__
+ return true;
+#else
+ return false; // musl
+#endif
+}
+
+static const size_t retain_size = 2 * M;
+
+bool os::should_trim_native_heap() {
+#ifdef __GLIBC__
+ bool rc = true;
+ // We try, using mallinfo, to predict whether a malloc_trim(3) will be beneficial.
+ //
+ // "mallinfo::keepcost" is no help even if manpage claims this to be the projected
+ // trim size. In practice it is just a very small value with no relation to the actual
+ // effect trimming will have.
+ //
+ // Our best bet is "mallinfo::fordblks", the total chunk size of free blocks. Since
+ // only free blocks can be trimmed, a very low bar is to require their combined size
+ // to be higher than our retain size. Note, however, that "mallinfo::fordblks" includes
+ // already-trimmed blocks, since glibc trims by calling madvice(MADV_DONT_NEED) on free
+ // chunks but does not update its bookkeeping.
+ //
+ // In the end we want to prevent obvious bogus attempts to trim, and for that fordblks
+ // is good enough.
+ os::Linux::glibc_mallinfo2 mi;
+ os::Linux::mallinfo_retval_t mirc = os::Linux::get_mallinfo(&mi);
+ const size_t total_free = mi.fordblks;
+ if (mirc == os::Linux::ok) {
+ rc = retain_size < total_free;
+ }
+ return rc;
+#else
+ return false; // musl
+#endif
+}
+
+bool os::trim_native_heap(os::size_change_t* rss_change) {
+#ifdef __GLIBC__
+ os::Linux::meminfo_t info1;
+ os::Linux::meminfo_t info2;
+
+ bool have_info1 = os::Linux::query_process_memory_info(&info1);
+ ::malloc_trim(retain_size);
+ bool have_info2 = have_info1 && os::Linux::query_process_memory_info(&info2);
+
+ if (have_info1 && have_info2 &&
+ info1.vmrss != -1 && info2.vmrss != -1 &&
+ info1.vmswap != -1 && info2.vmswap != -1) {
+ // Note: query_process_memory_info returns values in K
+ rss_change->before = (info1.vmrss + info1.vmswap) * K;
+ rss_change->after = (info2.vmrss + info2.vmswap) * K;
+ } else {
+ rss_change->after = rss_change->before = SIZE_MAX;
+ }
+
+ return true;
+#else
+ return false; // musl
+#endif
+}
\ No newline at end of file
diff --git a/hotspot/src/os/linux/vm/os_linux.hpp b/hotspot/src/os/linux/vm/os_linux.hpp
index 2bb3fd2..6c27bcb 100644
--- a/hotspot/src/os/linux/vm/os_linux.hpp
+++ b/hotspot/src/os/linux/vm/os_linux.hpp
@@ -243,7 +243,7 @@ class Linux {
public:
static pthread_condattr_t* condAttr() { return _condattr; }
- // Output structure for query_process_memory_info()
+ // Output structure for query_process_memory_info() (all values in KB)
struct meminfo_t {
ssize_t vmsize; // current virtual size
ssize_t vmpeak; // peak virtual size
@@ -338,40 +338,6 @@ private:
};
static NumaAllocationPolicy _current_numa_policy;
-#ifdef __GLIBC__
- struct glibc_mallinfo {
- int arena;
- int ordblks;
- int smblks;
- int hblks;
- int hblkhd;
- int usmblks;
- int fsmblks;
- int uordblks;
- int fordblks;
- int keepcost;
- };
-
- struct glibc_mallinfo2 {
- size_t arena;
- size_t ordblks;
- size_t smblks;
- size_t hblks;
- size_t hblkhd;
- size_t usmblks;
- size_t fsmblks;
- size_t uordblks;
- size_t fordblks;
- size_t keepcost;
- };
-
- typedef struct glibc_mallinfo (*mallinfo_func_t)(void);
- typedef struct glibc_mallinfo2 (*mallinfo2_func_t)(void);
-
- static mallinfo_func_t _mallinfo;
- static mallinfo2_func_t _mallinfo2;
-#endif
-
public:
static int sched_getcpu() { return _sched_getcpu != NULL ? _sched_getcpu() : -1; }
static int numa_node_to_cpus(int node, unsigned long *buffer, int bufferlen) {
@@ -484,6 +450,27 @@ public:
return false;
}
}
+
+#ifdef __GLIBC__
+ struct glibc_mallinfo2 {
+ size_t arena;
+ size_t ordblks;
+ size_t smblks;
+ size_t hblks;
+ size_t hblkhd;
+ size_t usmblks;
+ size_t fsmblks;
+ size_t uordblks;
+ size_t fordblks;
+ size_t keepcost;
+ };
+ enum mallinfo_retval_t { ok, error, ok_but_possibly_wrapped };
+ // get_mallinfo() is a wrapper for mallinfo/mallinfo2. It will prefer mallinfo2() if found.
+ // If we only have mallinfo(), values may be 32-bit truncated, which is signaled via
+ // "ok_but_possibly_wrapped".
+ static mallinfo_retval_t get_mallinfo(glibc_mallinfo2* out);
+#endif
+
};
diff --git a/hotspot/src/os/linux/vm/trimCHeapDCmd.cpp b/hotspot/src/os/linux/vm/trimCHeapDCmd.cpp
index 95d03d9..39d47a3 100644
--- a/hotspot/src/os/linux/vm/trimCHeapDCmd.cpp
+++ b/hotspot/src/os/linux/vm/trimCHeapDCmd.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 SAP SE. All rights reserved.
+ * Copyright (c) 2022 SAP SE. All rights reserved.
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -25,53 +25,28 @@
#include "precompiled.hpp"
#include "runtime/os.hpp"
+#include "trimCHeapDCmd.hpp"
#include "utilities/debug.hpp"
#include "utilities/ostream.hpp"
-#include "trimCHeapDCmd.hpp"
+#include "utilities/globalDefinitions.hpp"
#include <malloc.h>
void TrimCLibcHeapDCmd::execute(DCmdSource source, TRAPS) {
-#ifdef __GLIBC__
- stringStream ss_report(1024); // Note: before calling trim
-
- os::Linux::meminfo_t info1;
- os::Linux::meminfo_t info2;
- // Query memory before...
- bool have_info1 = os::Linux::query_process_memory_info(&info1);
-
- _output->print_cr("Attempting trim...");
- ::malloc_trim(0);
- _output->print_cr("Done.");
-
- // ...and after trim.
- bool have_info2 = os::Linux::query_process_memory_info(&info2);
-
- // Print report both to output stream as well to UL
- bool wrote_something = false;
- if (have_info1 && have_info2) {
- if (info1.vmsize != -1 && info2.vmsize != -1) {
- ss_report.print_cr("Virtual size before: " SSIZE_FORMAT "k, after: " SSIZE_FORMAT "k, (" SSIZE_FORMAT "k)",
- info1.vmsize, info2.vmsize, (info2.vmsize - info1.vmsize));
- wrote_something = true;
- }
- if (info1.vmrss != -1 && info2.vmrss != -1) {
- ss_report.print_cr("RSS before: " SSIZE_FORMAT "k, after: " SSIZE_FORMAT "k, (" SSIZE_FORMAT "k)",
- info1.vmrss, info2.vmrss, (info2.vmrss - info1.vmrss));
- wrote_something = true;
- }
- if (info1.vmswap != -1 && info2.vmswap != -1) {
- ss_report.print_cr("Swap before: " SSIZE_FORMAT "k, after: " SSIZE_FORMAT "k, (" SSIZE_FORMAT "k)",
- info1.vmswap, info2.vmswap, (info2.vmswap - info1.vmswap));
- wrote_something = true;
+ if (os::can_trim_native_heap()) {
+ os::size_change_t sc;
+ if (os::trim_native_heap(&sc)) {
+ _output->print("Trim native heap: ");
+ if (sc.after != SIZE_MAX) {
+ const size_t delta = sc.after < sc.before ? (sc.before - sc.after) : (sc.after - sc.before);
+ const char sign = sc.after < sc.before ? '-' : '+';
+ _output->print_cr("RSS+Swap: " PROPERFMT "->" PROPERFMT " (%c" PROPERFMT ")",
+ PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), sign, PROPERFMTARGS(delta));
+ } else {
+ _output->print_cr("(no details available).");
+ }
}
+ } else {
+ _output->print_cr("Not available.");
}
- if (!wrote_something) {
- ss_report.print_raw("No details available.");
- }
-
- _output->print_raw(ss_report.base());
-#else
- _output->print_cr("Not available.");
-#endif
}
diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp
index 500a412..25122de 100644
--- a/hotspot/src/os/windows/vm/os_windows.cpp
+++ b/hotspot/src/os/windows/vm/os_windows.cpp
@@ -5957,3 +5957,7 @@ void TestReserveMemorySpecial_test() {
}
#endif // PRODUCT
+// stubbed-out trim-native support
+bool os::can_trim_native_heap() { return false; }
+bool os::should_trim_native_heap() { return false; }
+bool os::trim_native_heap(os::size_change_t* rss_change) { return false; }
\ No newline at end of file
diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
index ba156a2..7188925 100644
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
@@ -53,6 +53,7 @@
#include "gc_implementation/shared/gcTimer.hpp"
#include "gc_implementation/shared/gcTrace.hpp"
#include "gc_implementation/shared/gcTraceTime.hpp"
+#include "gc_implementation/shared/gcTrimNativeHeap.hpp"
#include "gc_implementation/shared/isGCActiveMark.hpp"
#include "memory/allocation.hpp"
#include "memory/heapInspection.hpp"
@@ -1304,6 +1305,9 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
TraceCollectorStats tcs(g1mm()->full_collection_counters());
TraceMemoryManagerStats tms(true /* fullGC */, gc_cause());
+ // Pause native trimming for the duration of the GC
+ GCTrimNative::pause_periodic_trim();
+
double start = os::elapsedTime();
g1_policy()->record_full_collection_start();
@@ -1546,6 +1550,8 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
gc_timer->register_gc_end();
gc_tracer->report_gc_end(gc_timer->gc_end(), gc_timer->time_partitions());
+
+ GCTrimNative::schedule_trim();
}
return true;
}
diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp
index 74c1584..1c47125 100644
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp
@@ -36,6 +36,7 @@
#include "gc_implementation/parallelScavenge/psScavenge.hpp"
#include "gc_implementation/parallelScavenge/vmPSOperations.hpp"
#include "gc_implementation/shared/gcHeapSummary.hpp"
+#include "gc_implementation/shared/gcTrimNativeHeap.hpp"
#include "gc_implementation/shared/gcWhen.hpp"
#include "memory/gcLocker.inline.hpp"
#include "oops/oop.inline.hpp"
@@ -147,6 +148,8 @@ void ParallelScavengeHeap::post_initialize() {
PSMarkSweep::initialize();
}
PSPromotionManager::initialize();
+
+ GCTrimNative::initialize(true);
}
void ParallelScavengeHeap::update_counters() {
diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp
index 3f103ee..26d64a1 100644
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp
+++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp
@@ -42,6 +42,7 @@
#include "gc_implementation/shared/gcTimer.hpp"
#include "gc_implementation/shared/gcTrace.hpp"
#include "gc_implementation/shared/gcTraceTime.hpp"
+#include "gc_implementation/shared/gcTrimNativeHeap.hpp"
#include "gc_implementation/shared/isGCActiveMark.hpp"
#include "gc_interface/gcCause.hpp"
#include "memory/gcLocker.inline.hpp"
@@ -2008,6 +2009,9 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
return false;
}
+ // Pause native trimming for the duration of the GC
+ GCTrimNative::pause_periodic_trim();
+
ParallelScavengeHeap* heap = gc_heap();
_gc_timer.register_gc_start();
@@ -2182,6 +2186,8 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) {
// Resize the metaspace capactiy after a collection
MetaspaceGC::compute_new_size();
+ GCTrimNative::schedule_trim();
+
if (TraceGen1Time) accumulated_time()->stop();
if (PrintGC) {
diff --git a/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp b/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp
index e39fd7a..024499a 100644
--- a/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp
+++ b/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. 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
@@ -40,12 +40,12 @@ ConcurrentGCThread::ConcurrentGCThread() :
_should_terminate(false), _has_terminated(false) {
};
-void ConcurrentGCThread::create_and_start() {
+void ConcurrentGCThread::create_and_start(ThreadPriority prio) {
if (os::create_thread(this, os::cgc_thread)) {
// XXX: need to set this to low priority
// unless "agressive mode" set; priority
// should be just less than that of VMThread.
- os::set_priority(this, NearMaxPriority);
+ os::set_priority(this, prio);
if (!_should_terminate && !DisableStartThread) {
os::start_thread(this);
}
@@ -63,7 +63,7 @@ void ConcurrentGCThread::initialize_in_thread() {
void ConcurrentGCThread::wait_for_universe_init() {
MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
while (!is_init_completed() && !_should_terminate) {
- CGC_lock->wait(Mutex::_no_safepoint_check_flag, 200);
+ CGC_lock->wait(Mutex::_no_safepoint_check_flag, 1);
}
}
diff --git a/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp b/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp
index e87228b..1e16bf7 100644
--- a/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp
+++ b/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. 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
@@ -33,7 +33,7 @@ class ConcurrentGCThread: public NamedThread {
friend class VMStructs;
protected:
- bool _should_terminate;
+ bool volatile _should_terminate;
bool _has_terminated;
enum CGC_flag_type {
@@ -50,7 +50,7 @@ protected:
static int reset_CGC_flag(int b) { return _CGC_flag &= ~b; }
// Create and start the thread (setting it's priority high.)
- void create_and_start();
+ void create_and_start(ThreadPriority prio = NearMaxPriority);
// Do initialization steps in the thread: record stack base and size,
// init thread local storage, set JNI handle block.
diff --git a/hotspot/src/share/vm/gc_implementation/shared/gcTrimNativeHeap.cpp b/hotspot/src/share/vm/gc_implementation/shared/gcTrimNativeHeap.cpp
new file mode 100644
index 0000000..b9bac56
--- /dev/null
+++ b/hotspot/src/share/vm/gc_implementation/shared/gcTrimNativeHeap.cpp
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2022 SAP SE. All rights reserved.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved.
+ *
+ * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc_implementation/shared/concurrentGCThread.hpp"
+#include "gc_implementation/shared/gcTrimNativeHeap.hpp"
+#include "gc_implementation/g1/g1_globals.hpp"
+#include "runtime/globals.hpp"
+#include "runtime/globals_extension.hpp"
+#include "runtime/mutex.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/os.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/ostream.hpp"
+#include "utilities/ticks.hpp"
+
+bool GCTrimNative::_async_mode = false;
+double GCTrimNative::_next_trim_not_before = 0;
+
+// GCTrimNative works in two modes:
+//
+// - async mode, where GCTrimNative runs a trimmer thread on behalf of the GC.
+// The trimmer thread will be doing all the trims, both periodically and
+// triggered from outside via GCTrimNative::schedule_trim().
+//
+// - synchronous mode, where the GC does the trimming itself in its own thread,
+// via GCTrimNative::should_trim() and GCTrimNative::execute_trim().
+//
+// The mode is set as argument to GCTrimNative::initialize().
+
+class NativeTrimmer : public ConcurrentGCThread {
+
+ Monitor* _lock;
+ volatile jlong _paused;
+ static NativeTrimmer* _the_trimmer;
+
+public:
+
+ virtual void run() {
+ initialize_in_thread();
+ wait_for_universe_init();
+
+ assert(GCTrimNativeHeap, "Sanity");
+ assert(os::can_trim_native_heap(), "Sanity");
+
+ gclog_or_tty->print_cr("NativeTrimmer started.");
+
+ // Note: GCTrimNativeHeapInterval=0 -> zero wait time -> indefinite waits, disabling periodic trim
+ const int64_t delay_ms = GCTrimNativeHeapInterval * 1000;
+ for (;;) {
+ MonitorLockerEx ml(_lock, Mutex::_no_safepoint_check_flag);
+ ml.wait(Mutex::_no_safepoint_check_flag, delay_ms);
+ if (_should_terminate) {
+ gclog_or_tty->print_cr("NativeTrimmer stopped.");
+ break;
+ }
+ jlong paused = Atomic::load(&_paused);
+ if (!paused && os::should_trim_native_heap()) {
+ GCTrimNative::do_trim();
+ }
+ }
+
+ terminate();
+ }
+
+ void stop() {
+ {
+ MutexLockerEx ml(Terminator_lock);
+ _should_terminate = true;
+ }
+
+ wakeup();
+
+ {
+ MutexLockerEx ml(Terminator_lock);
+ while (!_has_terminated) {
+ Terminator_lock->wait();
+ }
+ }
+ }
+
+protected:
+
+ void wakeup() {
+ MonitorLockerEx ml(_lock, Mutex::_no_safepoint_check_flag);
+ ml.notify_all();
+ }
+
+ void pause() {
+ Atomic::store(1, &_paused);
+ debug_only(gclog_or_tty->print_cr("NativeTrimmer paused"));
+ }
+
+ void unpause() {
+ Atomic::store(0, &_paused);
+ debug_only(gclog_or_tty->print_cr("NativeTrimmer unpaused"));
+ }
+
+public:
+
+ NativeTrimmer() :
+ _paused(0)
+ {
+ //Mutex::leaf+8 just for NativeTrimmer_lock
+ _lock = new (std::nothrow) Monitor(Mutex::leaf+8, "NativeTrimmer_lock", true);
+ set_name("NativeTrimmer Thread");
+ }
+
+ static bool is_enabled() {
+ return _the_trimmer != NULL;
+ }
+
+ static void start_trimmer() {
+ _the_trimmer = new NativeTrimmer();
+ _the_trimmer->create_and_start(NormPriority);
+ }
+
+ static void stop_trimmer() {
+ _the_trimmer->stop();
+ }
+
+ static void pause_periodic_trim() {
+ _the_trimmer->pause();
+ }
+
+ static void unpause_periodic_trim() {
+ _the_trimmer->unpause();
+ }
+
+ static void schedule_trim_now() {
+ _the_trimmer->unpause();
+ _the_trimmer->wakeup();
+ }
+
+}; // NativeTrimmer
+
+NativeTrimmer* NativeTrimmer::_the_trimmer = NULL;
+
+void GCTrimNative::do_trim() {
+ Ticks start = Ticks::now();
+ os::size_change_t sc;
+ if (os::trim_native_heap(&sc)) {
+ Tickspan trim_time = (Ticks::now() - start);
+ if (sc.after != SIZE_MAX) {
+ const size_t delta = sc.after < sc.before ? (sc.before - sc.after) : (sc.after - sc.before);
+ const char sign = sc.after < sc.before ? '-' : '+';
+ gclog_or_tty->print_cr("Trim native heap: RSS+Swap: " PROPERFMT "->" PROPERFMT " (%c" PROPERFMT "), %1.3fms",
+ PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), sign, PROPERFMTARGS(delta),
+ trim_time.seconds() * 1000);
+ } else {
+ gclog_or_tty->print_cr("Trim native heap (no details)");
+ }
+ }
+}
+
+/// GCTrimNative outside facing methods
+
+void GCTrimNative::initialize(bool async_mode) {
+
+ if (GCTrimNativeHeap) {
+
+ if (!os::can_trim_native_heap()) {
+ FLAG_SET_ERGO(bool, GCTrimNativeHeap, false);
+ gclog_or_tty->print_cr("GCTrimNativeHeap disabled - trim-native not supported on this platform.");
+ return;
+ }
+
+ debug_only(gclog_or_tty->print_cr("GCTrimNativeHeap enabled."));
+
+ _async_mode = async_mode;
+
+ // If we are to run the trimmer on behalf of the GC:
+ if (_async_mode) {
+ NativeTrimmer::start_trimmer();
+ }
+
+ _next_trim_not_before = GCTrimNativeHeapInterval;
+ }
+}
+
+void GCTrimNative::cleanup() {
+ if (GCTrimNativeHeap) {
+ if (_async_mode) {
+ NativeTrimmer::stop_trimmer();
+ }
+ }
+}
+
+bool GCTrimNative::should_trim(bool ignore_delay) {
+ return
+ GCTrimNativeHeap && os::can_trim_native_heap() &&
+ (ignore_delay || (GCTrimNativeHeapInterval > 0 && os::elapsedTime() > _next_trim_not_before)) &&
+ os::should_trim_native_heap();
+}
+
+void GCTrimNative::execute_trim() {
+ if (GCTrimNativeHeap) {
+ assert(!_async_mode, "Only call for non-async mode");
+ do_trim();
+ _next_trim_not_before = os::elapsedTime() + GCTrimNativeHeapInterval;
+ }
+}
+
+void GCTrimNative::pause_periodic_trim() {
+ if (GCTrimNativeHeap) {
+ assert(_async_mode, "Only call for async mode");
+ NativeTrimmer::pause_periodic_trim();
+ }
+}
+
+void GCTrimNative::unpause_periodic_trim() {
+ if (GCTrimNativeHeap) {
+ assert(_async_mode, "Only call for async mode");
+ NativeTrimmer::unpause_periodic_trim();
+ }
+}
+
+void GCTrimNative::schedule_trim() {
+ if (GCTrimNativeHeap) {
+ assert(_async_mode, "Only call for async mode");
+ NativeTrimmer::schedule_trim_now();
+ }
+}
diff --git a/hotspot/src/share/vm/gc_implementation/shared/gcTrimNativeHeap.hpp b/hotspot/src/share/vm/gc_implementation/shared/gcTrimNativeHeap.hpp
new file mode 100644
index 0000000..f586093
--- /dev/null
+++ b/hotspot/src/share/vm/gc_implementation/shared/gcTrimNativeHeap.hpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2022 SAP SE. All rights reserved.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, Huawei Technologies Co., Ltd. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_GC_SHARED_GCTRIMNATIVEHEAP_HPP
+#define SHARE_GC_SHARED_GCTRIMNATIVEHEAP_HPP
+
+#include "memory/allocation.hpp"
+
+class NativeTrimmer;
+
+class GCTrimNative : public AllStatic {
+ friend class NativeTrimmer;
+
+ static bool _async_mode;
+ static double _next_trim_not_before;
+
+ static void do_trim();
+
+public:
+
+ static void initialize(bool async_mode);
+ static void cleanup();
+
+ // Returns true if:
+ // - trimming is enabled and possible
+ // - trimming may have an actual effect (guess)
+ // - delay timer has expired (unless ignore_delay is true)
+ static bool should_trim(bool ignore_delay);
+
+ // Execute trim-native in this thread
+ static void execute_trim();
+
+ // Pause/unpause periodic trim
+ static void pause_periodic_trim();
+ static void unpause_periodic_trim();
+
+ // Schedule an explicit trim now; if periodic trims had been
+ // paused, they are unpaused.
+ static void schedule_trim();
+
+};
+
+#endif // SHARE_GC_SHARED_GCTRIMNATIVEHEAP_HPP
diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp
index 20fbbfd..7df3d68 100644
--- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp
+++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp
@@ -58,6 +58,7 @@
#if INCLUDE_ALL_GCS
#include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp"
#include "gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp"
+#include "gc_implementation/shared/gcTrimNativeHeap.hpp"
#endif // INCLUDE_ALL_GCS
#if INCLUDE_JFR
#include "jfr/jfr.hpp"
@@ -572,6 +573,11 @@ void GenCollectedHeap::do_collection(bool full,
update_full_collections_completed();
}
+ // Trim the native heap, without a delay since this is a full gc
+ if (full && GCTrimNative::should_trim(true)) {
+ GCTrimNative::execute_trim();
+ }
+
// Track memory usage and detect low memory after GC finishes
MemoryService::track_memory_usage();
diff --git a/hotspot/src/share/vm/memory/sharedHeap.cpp b/hotspot/src/share/vm/memory/sharedHeap.cpp
index ef22f01..8c02320 100644
--- a/hotspot/src/share/vm/memory/sharedHeap.cpp
+++ b/hotspot/src/share/vm/memory/sharedHeap.cpp
@@ -26,6 +26,7 @@
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
+#include "gc_implementation/shared/gcTrimNativeHeap.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "memory/sharedHeap.hpp"
#include "oops/oop.inline.hpp"
@@ -104,6 +105,11 @@ void SharedHeap::set_barrier_set(BarrierSet* bs) {
void SharedHeap::post_initialize() {
CollectedHeap::post_initialize();
ref_processing_init();
+ if (!UseSerialGC) {
+ GCTrimNative::initialize(true);
+ } else {
+ GCTrimNative::initialize(false); // false since we will call trim inside the collecting thread
+ }
}
void SharedHeap::ref_processing_init() {}
diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp
index 0dab18e..ec48c48 100644
--- a/hotspot/src/share/vm/runtime/globals.hpp
+++ b/hotspot/src/share/vm/runtime/globals.hpp
@@ -3387,6 +3387,16 @@ class CommandLineFlags {
"Number of entries we will try to leave on the stack " \
"during parallel gc") \
\
+ experimental(bool, GCTrimNativeHeap, false, \
+ "GC will attempt to trim the native heap periodically and at " \
+ "full GCs.") \
+ \
+ experimental(uintx, GCTrimNativeHeapInterval, 60, \
+ "If GCTrimNativeHeap is enabled: interval time, in seconds, in " \
+ "which the VM will attempt to trim the native heap. A value of " \
+ "0 disables periodic trimming while leaving trimming at full gc " \
+ "enabled.") \
+ \
/* stack parameters */ \
product_pd(intx, StackYellowPages, \
"Number of yellow zone (recoverable overflows) pages") \
diff --git a/hotspot/src/share/vm/runtime/init.cpp b/hotspot/src/share/vm/runtime/init.cpp
index d15e40d..d2e0f22 100644
--- a/hotspot/src/share/vm/runtime/init.cpp
+++ b/hotspot/src/share/vm/runtime/init.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. 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
@@ -166,8 +166,7 @@ void exit_globals() {
}
}
-
-static bool _init_completed = false;
+static volatile bool _init_completed = false;
bool is_init_completed() {
return _init_completed;
diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp
index 4f290c8..54b980d 100644
--- a/hotspot/src/share/vm/runtime/java.cpp
+++ b/hotspot/src/share/vm/runtime/java.cpp
@@ -30,6 +30,7 @@
#include "code/codeCache.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/compilerOracle.hpp"
+#include "gc_implementation/shared/gcTrimNativeHeap.hpp"
#include "interpreter/bytecodeHistogram.hpp"
#include "jfr/jfrEvents.hpp"
#include "jfr/support/jfrThreadId.hpp"
@@ -509,6 +510,8 @@ void before_exit(JavaThread * thread) {
StatSampler::disengage();
StatSampler::destroy();
+ GCTrimNative::cleanup();
+
// Stop concurrent GC threads
Universe::heap()->stop();
diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp
index 7ae49fd..acc57f4 100644
--- a/hotspot/src/share/vm/runtime/os.hpp
+++ b/hotspot/src/share/vm/runtime/os.hpp
@@ -333,6 +333,17 @@ class os: AllStatic {
static bool uncommit_memory(char* addr, size_t bytes);
static bool release_memory(char* addr, size_t bytes);
+ // Does the platform support trimming the native heap?
+ static bool can_trim_native_heap();
+
+ // Does the platform recommend trimming?
+ static bool should_trim_native_heap();
+
+ // Trim the C-heap. Returns RSS size change and optionally return the rss size change.
+ // If trim was done but size change could not be obtained, SIZE_MAX is returned for after size.
+ struct size_change_t { size_t before; size_t after; };
+ static bool trim_native_heap(size_change_t* rss_change);
+
// Touch memory pages that cover the memory range from start to end (exclusive)
// to make the OS back the memory range with actual memory.
// Current implementation may not touch the last page if unaligned addresses
diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp
index 25f6f02..12eea20 100644
--- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp
+++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp
@@ -260,6 +260,9 @@ inline T byte_size_in_proper_unit(T s) {
}
}
+#define PROPERFMT SIZE_FORMAT "%s"
+#define PROPERFMTARGS(S) byte_size_in_proper_unit(S), proper_unit_for_byte_size(S)
+
//----------------------------------------------------------------------------------------------------
// VM type definitions
diff --git a/hotspot/test/gc/TestTrimNative.java b/hotspot/test/gc/TestTrimNative.java
new file mode 100644
index 0000000..58d5405
--- /dev/null
+++ b/hotspot/test/gc/TestTrimNative.java
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 2022 SAP SE. All rights reserved.
+ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, Huawei Technologies Co., Ltd. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package gc;
+
+/*
+ * All these tests test the trim-native feature for all GCs.
+ * Trim-native is the ability to trim the C-heap as part of the GC cycle.
+ * This feature is controlled by -XX:+GCTrimNativeHeap (by default off).
+ * Trimming happens on full gc for all gcs. Shenandoah and G1 also support
+ * concurrent trimming (Shenandoah supports this without any ties to java
+ * heap occupancy).
+ *
+ */
+
+//// full gc tests /////
+
+/*
+ * @test id=fullgc-serial
+ * @summary Test that GCTrimNativeHeap works with Serial
+ * @requires vm.gc=="Serial"
+ * @requires os.family=="linux"
+ * @modules java.base/jdk.internal.misc
+ * @library /testlibrary
+ * @run driver gc.TestTrimNative test-fullgc serial
+ */
+
+/*
+ * @test id=fullgc-parallel
+ * @summary Test that GCTrimNativeHeap works with Parallel
+ * @requires vm.gc=="Parallel"
+ * @requires os.family=="linux"
+ * @modules java.base/jdk.internal.misc
+ * @library /testlibrary
+ * @run driver gc.TestTrimNative test-fullgc parallel
+ */
+
+/*
+ * @test id=fullgc-g1
+ * @summary Test that GCTrimNativeHeap works with G1
+ * @requires vm.gc=="G1"
+ * @requires os.family=="linux"
+ * @modules java.base/jdk.internal.misc
+ * @library /testlibrary
+ * @run driver gc.TestTrimNative test-fullgc g1
+ */
+
+//// auto mode tests /////
+
+// Note: not serial, since it does not do periodic trimming, only trimming on full gc
+
+/*
+ * @test id=auto-parallel
+ * @summary Test that GCTrimNativeHeap works with Parallel
+ * @requires vm.gc=="Parallel"
+ * @requires os.family=="linux"
+ * @modules java.base/jdk.internal.misc
+ * @library /testlibrary
+ * @run driver gc.TestTrimNative test-auto parallel
+ */
+
+/*
+ * @test id=auto-g1
+ * @summary Test that GCTrimNativeHeap works with G1
+ * @requires vm.gc=="G1"
+ * @requires os.family=="linux"
+ * @modules java.base/jdk.internal.misc
+ * @library /testlibrary
+ * @run driver gc.TestTrimNative test-auto g1
+ */
+
+
+//// test-auto-high-interval interval test /////
+
+// Note: not serial, since it does not do periodic trimming, only trimming on full gc
+
+/*
+ * @test id=auto-high-interval-parallel
+ * @summary Test that a high GCTrimNativeHeapInterval effectively disables automatic trimming
+ * @requires vm.gc=="Parallel"
+ * @requires os.family=="linux"
+ * @modules java.base/jdk.internal.misc
+ * @library /testlibrary
+ * @run driver gc.TestTrimNative test-auto-high-interval parallel
+ */
+
+/*
+ * @test id=auto-high-interval-g1
+ * @summary Test that a high GCTrimNativeHeapInterval effectively disables automatic trimming
+ * @requires vm.gc=="G1"
+ * @requires os.family=="linux"
+ * @modules java.base/jdk.internal.misc
+ * @library /testlibrary
+ * @run driver gc.TestTrimNative test-auto-high-interval g1
+ */
+
+//// test-auto-interval-0 test /////
+
+// Note: not serial, since it does not do periodic trimming, only trimming on full gc
+
+/*
+ * @test id=auto-zero-interval-parallel
+ * @summary Test that a GCTrimNativeHeapInterval=0 disables periodic trimming
+ * @requires vm.gc=="Parallel"
+ * @requires os.family=="linux"
+ * @modules java.base/jdk.internal.misc
+ * @library /testlibrary
+ * @run driver gc.TestTrimNative test-auto-zero-interval parallel
+ */
+
+/*
+ * @test id=auto-zero-interval-g1
+ * @summary Test that a GCTrimNativeHeapInterval=0 disables periodic trimming
+ * @requires vm.gc=="G1"
+ * @requires os.family=="linux"
+ * @modules java.base/jdk.internal.misc
+ * @library /testlibrary
+ * @run driver gc.TestTrimNative test-auto-zero-interval g1
+ */
+
+// Other tests
+
+/*
+ * @test id=off-explicit
+ * @summary Test that -GCTrimNative disables the feature
+ * @requires os.family=="linux"
+ * @modules java.base/jdk.internal.misc
+ * @library /testlibrary
+ * @run driver gc.TestTrimNative test-off-explicit
+ */
+
+/*
+ * @test id=off-by-default
+ * @summary Test that GCTrimNative is off by default
+ * @requires os.family=="linux"
+ * @modules java.base/jdk.internal.misc
+ * @library /testlibrary
+ * @run driver gc.TestTrimNative test-off-by-default
+ */
+
+/*
+ * @test id=off-on-other-platforms
+ * @summary Test that GCTrimNative is off on unsupportive platforms
+ * @requires os.family!="linux"
+ * @modules java.base/jdk.internal.misc
+ * @library /testlibrary
+ * @run driver gc.TestTrimNative test-off-on-other-platforms
+ */
+
+import sun.misc.Unsafe;
+import com.oracle.java.testlibrary.*;
+
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class TestTrimNative {
+
+ // Actual RSS increase is a lot larger than 4 MB. Depends on glibc overhead, and NMT malloc headers in debug VMs.
+ // We need small-grained allocations to make sure they actually increase RSS (all touched) and to see the
+ // glibc-retaining-memory effect.
+ static final int szAllocations = 16;
+ static final int totalAllocationsSize = 16 * 1024 * 1024; // 16 MB total
+ static final int numAllocations = totalAllocationsSize / szAllocations;
+
+ static long[] ptrs = new long[numAllocations];
+
+ enum Unit {
+ B(1), K(1024), M(1024*1024), G(1024*1024*1024);
+ public final long size;
+ Unit(long size) { this.size = size; }
+ }
+
+ enum GC {
+ serial, parallel, g1, shenandoah, z;
+ String getSwitchName() {
+ String s = name();
+ return "-XX:+Use" + s.substring(0, 1).toUpperCase() + s.substring(1) + "GC";
+ }
+ boolean isZ() { return this == GC.z; }
+ boolean isSerial() { return this == GC.serial; }
+ boolean isParallel() { return this == GC.parallel; }
+ boolean isG1() { return this == GC.g1; }
+ boolean isShenandoah() { return this == GC.shenandoah; }
+ }
+
+ static private boolean usesNativeTrimmer(GC gc) {
+ return gc.isG1() || gc.isParallel() || gc.isZ();
+ }
+
+ static private final OutputAnalyzer runTestWithOptions(String[] extraOptions, String[] testArgs) throws Exception {
+
+ List<String> allOptions = new ArrayList<String>();
+ allOptions.add("-XX:+UnlockExperimentalVMOptions");
+ allOptions.addAll(Arrays.asList(extraOptions));
+ allOptions.add("-Xmx128m");
+ allOptions.add("-Xms128m"); // Stabilize RSS
+ allOptions.add("-XX:+AlwaysPreTouch"); // Stabilize RSS
+
+ allOptions.add(TestTrimNative.class.getName());
+ allOptions.add("RUN");
+ allOptions.addAll(Arrays.asList(testArgs));
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(allOptions.toArray(new String[0]));
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldHaveExitValue(0);
+ return output;
+
+ }
+
+ /**
+ * Given JVM output, look for a log line that describes a successful negative trim in the megabyte range
+ * like this:
+ * "[2.053s][debug][gc,trim] Trim native heap (retain size: 5120K): RSS+Swap: 271M->223M (-49112K), 2.834ms"
+ * (Note: we use the "properXXX" print routines, therefore units can differ)
+ * Check that the sum of all trim log lines comes to a total RSS reduction in the MB range
+ * @param output
+ * @param minExpected min number of trim lines expected in UL log
+ * @param maxExpected max number of trim lines expected in UL log
+ */
+ private final static void parseOutputAndLookForNegativeTrim(OutputAnalyzer output, int minExpected, int maxExpected) {
+ output.reportDiagnosticSummary();
+ List<String> lines = output.asLines();
+ Pattern pat = Pattern.compile(".*\\[gc,trim\\] Trim native heap.*RSS\\+Swap: (\\d+)([KMB])->(\\d+)([KMB]).*");
+ int numTrimsFound = 0;
+ long rssReductionTotal = 0;
+ for (String line : lines) {
+ Matcher mat = pat.matcher(line);
+ if (mat.matches()) {
+ long rss1 = Long.parseLong(mat.group(1)) * Unit.valueOf(mat.group(2)).size;
+ long rss2 = Long.parseLong(mat.group(3)) * Unit.valueOf(mat.group(4)).size;
+ System.out.println("Parsed Trim Line. rss1: " + rss1 + " rss2: " + rss2);
+ if (rss1 > rss2) {
+ rssReductionTotal += (rss1 - rss2);
+ }
+ numTrimsFound ++;
+ }
+ if (numTrimsFound > maxExpected) {
+ throw new RuntimeException("Abnormal high number of trim attempts found (more than " + maxExpected +
+ "). Does the interval setting not work?");
+ }
+ }
+ if (numTrimsFound < minExpected) {
+ throw new RuntimeException("We found fewer trim lines in UL log than expected (expected " + minExpected +
+ ", found " + numTrimsFound + ".");
+ }
+ // This is very fuzzy. We malloced X, free'd X, trimmed, measured the combined effect of all reductions.
+ // This does not take into effect mallocs or frees that may happen concurrently. But we expect to see *some*
+ // reduction somewhere. Test with a fudge factor.
+ float fudge = 0.8f;
+ long expectedMinimalReduction = (long) (totalAllocationsSize * fudge);
+ if (rssReductionTotal < expectedMinimalReduction) {
+ throw new RuntimeException("We did not see the expected RSS reduction in the UL log. Expected (with fudge)" +
+ " to see at least a combined reduction of " + expectedMinimalReduction + ".");
+ }
+ }
+
+ // Test that GCTrimNativeHeap=1 causes a trim-native on full gc
+ static private final void testWithFullGC(GC gc) throws Exception {
+ System.out.println("testWithFullGC");
+ int sleeptime_secs = 2;
+ OutputAnalyzer output = runTestWithOptions (
+ new String[] { gc.getSwitchName(), "-XX:+GCTrimNativeHeap" },
+ new String[] { "true" /* full gc */, String.valueOf(sleeptime_secs * 1000) /* ms after peak */ }
+ );
+ // With default interval time of 30 seconds, auto trimming should never kick in, so the only
+ // log line we expect to see is the one from the full-gc induced trim.
+ parseOutputAndLookForNegativeTrim(output, 1, 1);
+ // For GCs that use the NativeTrimmer, we want to see the NativeTrimmer paused during the GC, as well as
+ // started and shut down properly.
+ if (usesNativeTrimmer(gc)) {
+ output.shouldContain("NativeTrimmer started");
+ output.shouldContain("NativeTrimmer paused");
+ output.shouldContain("NativeTrimmer unpaused");
+ output.shouldContain("NativeTrimmer stopped");
+ } else {
+ output.shouldNotContain("NativeTrimmer");
+ }
+ }
+
+ // Test that GCTrimNativeHeap=1 causes a trim-native automatically, without GC (for now, shenandoah only)
+ static private final void testAuto(GC gc) throws Exception {
+ System.out.println("testAuto");
+ long t1 = System.currentTimeMillis();
+ int sleeptime_secs = 4;
+ OutputAnalyzer output = runTestWithOptions (
+ new String[] { gc.getSwitchName(), "-XX:+GCTrimNativeHeap", "-XX:GCTrimNativeHeapInterval=1" },
+ new String[] { "false" /* full gc */, String.valueOf(sleeptime_secs * 1000) /* ms after peak */ }
+ );
+ long t2 = System.currentTimeMillis();
+ int runtime_s = (int)((t2 - t1) / 1000);
+ // With an interval time of 1 second and a runtime of 6..x seconds we expect to see x log lines (+- fudge factor).
+ parseOutputAndLookForNegativeTrim(output, runtime_s - 4, runtime_s + 2);
+ }
+
+ // Test that trim-native correctly honors interval
+ static private final void testAutoWithHighInterval(GC gc) throws Exception {
+ // We pass a very high interval. This should disable the feature for this short-lived test, we should see no trim
+ System.out.println("testAutoWithHighInterval");
+ OutputAnalyzer output = runTestWithOptions (
+ new String[] { gc.getSwitchName(), "-XX:+GCTrimNativeHeap", "-XX:GCTrimNativeHeapInterval=30" },
+ new String[] { "false" /* full gc */, "6000" /* ms after peak */ }
+ );
+ output.shouldNotContain("Trim native heap");
+ }
+
+ // Test that trim-native correctly honors interval
+ static private final void testAutoWithZeroInterval(GC gc) throws Exception {
+ // We pass a very high interval. This should disable the feature for this short-lived test, we should see no trim
+ System.out.println("testAutoWithHighInterval");
+ OutputAnalyzer output = runTestWithOptions (
+ new String[] { gc.getSwitchName(), "-XX:+GCTrimNativeHeap", "-XX:GCTrimNativeHeapInterval=0" },
+ new String[] { "false" /* full gc */, "6000" /* ms after peak */ }
+ );
+ output.shouldNotContain("Trim native heap");
+ }
+
+ // Test that trim-native gets disabled on platforms that don't support it.
+ static private final void testOffOnNonCompliantPlatforms() throws Exception {
+ // Logic is shared, so no need to test with every GC. Just use the default GC.
+ System.out.println("testOffOnNonCompliantPlatforms");
+ OutputAnalyzer output = runTestWithOptions (
+ new String[] { "-XX:+GCTrimNativeHeap" },
+ new String[] { "true" /* full gc */, "2000" /* ms after peak */ }
+ );
+ output.shouldContain("GCTrimNativeHeap disabled");
+ output.shouldNotContain("Trim native heap");
+ }
+
+ // Test that GCTrimNativeHeap=0 switches trim-native off
+ static private final void testOffExplicit() throws Exception {
+ // Logic is shared, so no need to test with every GC. Just use the default GC.
+ System.out.println("testOffExplicit");
+ OutputAnalyzer output = runTestWithOptions (
+ new String[] { "-XX:-GCTrimNativeHeap" },
+ new String[] { "true" /* full gc */, "2000" /* ms after peak */ }
+ );
+ output.shouldNotContain("Trim native heap");
+ }
+
+ // Test that trim-native is disabled by default
+ static private final void testOffByDefault() throws Exception {
+ // Logic is shared, so no need to test with every GC. Just use the default GC.
+ System.out.println("testOffByDefault");
+ OutputAnalyzer output = runTestWithOptions (
+ new String[] { },
+ new String[] { "true" /* full gc */, "2000" /* ms after peak */ }
+ );
+ output.shouldNotContain("Trim native heap");
+ }
+
+ public static void main(String[] args) throws Exception {
+
+ if (args.length == 0) {
+ throw new RuntimeException("Argument error");
+ }
+
+ if (args[0].equals("RUN")) {
+ boolean doFullGC = Boolean.parseBoolean(args[1]);
+
+ System.out.println("Will spike now...");
+ Field field = Unsafe.class.getDeclaredField("theUnsafe");
+ field.setAccessible(true);
+ Unsafe unsafe = (Unsafe) field.get(null);
+ for (int i = 0; i < numAllocations; i++) {
+ ptrs[i] = unsafe.allocateMemory(szAllocations);
+ unsafe.putByte(ptrs[i], (byte)0);
+ unsafe.putByte(ptrs[i] + szAllocations / 2, (byte)0);
+ }
+ for (int i = 0; i < numAllocations; i++) {
+ unsafe.freeMemory(ptrs[i]);
+ }
+ System.out.println("Done spiking.");
+
+ if (doFullGC) {
+ System.out.println("GC...");
+ System.gc();
+ }
+
+ // give GC time to react
+ int time = Integer.parseInt(args[2]);
+ System.out.println("Sleeping...");
+ Thread.sleep(time);
+ System.out.println("Done.");
+
+ return;
+
+ } else if (args[0].equals("test-fullgc")) {
+ final GC gc = GC.valueOf(args[1]);
+ testWithFullGC(gc);
+ } else if (args[0].equals("test-auto")) {
+ final GC gc = GC.valueOf(args[1]);
+ testAuto(gc);
+ } else if (args[0].equals("test-auto-high-interval")) {
+ final GC gc = GC.valueOf(args[1]);
+ testAutoWithHighInterval(gc);
+ } else if (args[0].equals("test-auto-zero-interval")) {
+ final GC gc = GC.valueOf(args[1]);
+ testAutoWithZeroInterval(gc);
+ } else if (args[0].equals("test-off-explicit")) {
+ testOffExplicit();
+ } else if (args[0].equals("test-off-by-default")) {
+ testOffByDefault();
+ } else if (args[0].equals("test-off-on-other-platforms")) {
+ testOffOnNonCompliantPlatforms();
+ } else {
+ throw new RuntimeException("Invalid test " + args[0]);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/hotspot/test/serviceability/dcmd/TrimLibcHeapTest.java b/hotspot/test/serviceability/dcmd/TrimLibcHeapTest.java
index 0fe8e35..131fa4c 100644
--- a/hotspot/test/serviceability/dcmd/TrimLibcHeapTest.java
+++ b/hotspot/test/serviceability/dcmd/TrimLibcHeapTest.java
@@ -29,7 +29,7 @@ import com.oracle.java.testlibrary.*;
* @test
* @summary Test of diagnostic command VM.trim_libc_heap
* @library /testlibrary
- * @requires os.family == "linux"
+ * @requires os.family=="linux"
* @modules java.base/jdk.internal.misc
* java.compiler
* java.management
@@ -40,10 +40,7 @@ public class TrimLibcHeapTest {
public void run(CommandExecutor executor) {
OutputAnalyzer output = executor.execute("System.trim_native_heap");
output.reportDiagnosticSummary();
- output.shouldMatch("(Done|Not available)"); // Not available could happen on Linux + non-glibc (eg. muslc)
- if (output.firstMatch("Done") != null) {
- output.shouldMatch("(Virtual size before|RSS before|Swap before|No details available)");
- }
+ output.shouldMatch(".*Trim native heap: RSS\\+Swap: \\d+[BKM]->\\d+[BKM].*");
}
@Test
--
1.8.3.1
1
https://gitee.com/DXwangg/openjdk-1.8.0.git
git@gitee.com:DXwangg/openjdk-1.8.0.git
DXwangg
openjdk-1.8.0
openjdk-1.8.0
master

搜索帮助