8296796: Provide clean, platform-agnostic interface to C-heap trimming
Reviewed-by: dholmes, rkennke
This commit is contained in:
parent
c50a9047b4
commit
0845b39caf
@ -52,4 +52,8 @@ inline bool os::must_commit_stack_guard_pages() {
|
||||
inline void os::map_stack_shadow_pages(address sp) {
|
||||
}
|
||||
|
||||
// stubbed-out trim-native support
|
||||
inline bool os::can_trim_native_heap() { return false; }
|
||||
inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; }
|
||||
|
||||
#endif // OS_AIX_OS_AIX_INLINE_HPP
|
||||
|
@ -55,4 +55,8 @@ inline bool os::must_commit_stack_guard_pages() {
|
||||
inline void os::map_stack_shadow_pages(address sp) {
|
||||
}
|
||||
|
||||
// stubbed-out trim-native support
|
||||
inline bool os::can_trim_native_heap() { return false; }
|
||||
inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; }
|
||||
|
||||
#endif // OS_BSD_OS_BSD_INLINE_HPP
|
||||
|
@ -5331,3 +5331,32 @@ void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {
|
||||
st->cr();
|
||||
}
|
||||
}
|
||||
|
||||
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 = rss_change != nullptr &&
|
||||
os::Linux::query_process_memory_info(&info1);
|
||||
::malloc_trim(0);
|
||||
bool have_info2 = rss_change != nullptr && have_info1 &&
|
||||
os::Linux::query_process_memory_info(&info2);
|
||||
ssize_t delta = (ssize_t) -1;
|
||||
if (rss_change != nullptr) {
|
||||
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
|
||||
}
|
||||
|
@ -47,4 +47,13 @@ inline bool os::must_commit_stack_guard_pages() {
|
||||
inline void os::map_stack_shadow_pages(address sp) {
|
||||
}
|
||||
|
||||
// Trim-native support
|
||||
inline bool os::can_trim_native_heap() {
|
||||
#ifdef __GLIBC__
|
||||
return true;
|
||||
#else
|
||||
return false; // musl
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // OS_LINUX_OS_LINUX_INLINE_HPP
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2022 SAP SE. All rights reserved.
|
||||
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -24,57 +24,29 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "os_linux.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/ostream.hpp"
|
||||
#include "runtime/os.inline.hpp"
|
||||
#include "trimCHeapDCmd.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/ostream.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());
|
||||
log_info(os)("malloc_trim:\n%s", ss_report.base());
|
||||
#else
|
||||
_output->print_cr("Not available.");
|
||||
#endif
|
||||
}
|
||||
|
@ -98,4 +98,8 @@ inline void PlatformMonitor::notify_all() {
|
||||
WakeAllConditionVariable(&_cond);
|
||||
}
|
||||
|
||||
// stubbed-out trim-native support
|
||||
inline bool os::can_trim_native_heap() { return false; }
|
||||
inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; }
|
||||
|
||||
#endif // OS_WINDOWS_OS_WINDOWS_INLINE_HPP
|
||||
|
@ -440,6 +440,15 @@ class os: AllStatic {
|
||||
static bool uncommit_memory(char* addr, size_t bytes, bool executable = false);
|
||||
static bool release_memory(char* addr, size_t bytes);
|
||||
|
||||
// Does the platform support trimming the native heap?
|
||||
static bool can_trim_native_heap();
|
||||
|
||||
// Trim the C-heap. Optionally returns working set size change (RSS+Swap) in *rss_change.
|
||||
// Note: If trimming succeeded but no size change information could be obtained,
|
||||
// rss_change.after will contain SIZE_MAX upon return.
|
||||
struct size_change_t { size_t before; size_t after; };
|
||||
static bool trim_native_heap(size_change_t* rss_change = nullptr);
|
||||
|
||||
// A diagnostic function to print memory mappings in the given range.
|
||||
static void print_memory_mappings(char* addr, size_t bytes, outputStream* st);
|
||||
// Prints all mappings
|
||||
|
@ -372,6 +372,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)
|
||||
|
||||
inline const char* exact_unit_for_byte_size(size_t s) {
|
||||
#ifdef _LP64
|
||||
if (s >= G && (s % G) == 0) {
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "runtime/os.inline.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "services/memTracker.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
@ -890,3 +890,27 @@ TEST_VM(os, is_first_C_frame) {
|
||||
EXPECT_FALSE(os::is_first_C_frame(&cur_frame));
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
#ifdef __GLIBC__
|
||||
TEST_VM(os, trim_native_heap) {
|
||||
EXPECT_TRUE(os::can_trim_native_heap());
|
||||
os::size_change_t sc;
|
||||
sc.before = sc.after = (size_t)-1;
|
||||
EXPECT_TRUE(os::trim_native_heap(&sc));
|
||||
tty->print_cr(SIZE_FORMAT "->" SIZE_FORMAT, sc.before, sc.after);
|
||||
// Regardless of whether we freed memory, both before and after
|
||||
// should be somewhat believable numbers (RSS).
|
||||
const size_t min = 5 * M;
|
||||
const size_t max = LP64_ONLY(20 * G) NOT_LP64(3 * G);
|
||||
ASSERT_LE(min, sc.before);
|
||||
ASSERT_GT(max, sc.before);
|
||||
ASSERT_LE(min, sc.after);
|
||||
ASSERT_GT(max, sc.after);
|
||||
// Should also work
|
||||
EXPECT_TRUE(os::trim_native_heap());
|
||||
}
|
||||
#else
|
||||
TEST_VM(os, trim_native_heap) {
|
||||
EXPECT_FALSE(os::can_trim_native_heap());
|
||||
}
|
||||
#endif // __GLIBC__
|
||||
|
@ -31,7 +31,7 @@ import jdk.test.lib.process.OutputAnalyzer;
|
||||
* @test
|
||||
* @summary Test of diagnostic command VM.trim_libc_heap
|
||||
* @library /test/lib
|
||||
* @requires os.family == "linux"
|
||||
* @requires (os.family=="linux") & !vm.musl
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.compiler
|
||||
* java.management
|
||||
@ -42,10 +42,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
|
||||
|
Loading…
x
Reference in New Issue
Block a user