Skip to content

Commit c54ecfb

Browse files
committed
8296796: Provide clean, platform-agnostic interface to C-heap trimming
Reviewed-by: stuefe Backport-of: 0845b39caf6f04dca9cb7a5852f05b4b5ffbc034
1 parent 67c5150 commit c54ecfb

File tree

10 files changed

+108
-52
lines changed

10 files changed

+108
-52
lines changed

src/hotspot/os/aix/os_aix.inline.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,8 @@ inline bool os::must_commit_stack_guard_pages() {
4747
inline void os::map_stack_shadow_pages(address sp) {
4848
}
4949

50+
// stubbed-out trim-native support
51+
inline bool os::can_trim_native_heap() { return false; }
52+
inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; }
53+
5054
#endif // OS_AIX_OS_AIX_INLINE_HPP

src/hotspot/os/bsd/os_bsd.inline.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,8 @@ inline bool os::must_commit_stack_guard_pages() {
5151
inline void os::map_stack_shadow_pages(address sp) {
5252
}
5353

54+
// stubbed-out trim-native support
55+
inline bool os::can_trim_native_heap() { return false; }
56+
inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; }
57+
5458
#endif // OS_BSD_OS_BSD_INLINE_HPP

src/hotspot/os/linux/os_linux.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5509,3 +5509,32 @@ void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {
55095509
st->cr();
55105510
}
55115511
}
5512+
5513+
bool os::trim_native_heap(os::size_change_t* rss_change) {
5514+
#ifdef __GLIBC__
5515+
os::Linux::meminfo_t info1;
5516+
os::Linux::meminfo_t info2;
5517+
5518+
bool have_info1 = rss_change != nullptr &&
5519+
os::Linux::query_process_memory_info(&info1);
5520+
::malloc_trim(0);
5521+
bool have_info2 = rss_change != nullptr && have_info1 &&
5522+
os::Linux::query_process_memory_info(&info2);
5523+
ssize_t delta = (ssize_t) -1;
5524+
if (rss_change != nullptr) {
5525+
if (have_info1 && have_info2 &&
5526+
info1.vmrss != -1 && info2.vmrss != -1 &&
5527+
info1.vmswap != -1 && info2.vmswap != -1) {
5528+
// Note: query_process_memory_info returns values in K
5529+
rss_change->before = (info1.vmrss + info1.vmswap) * K;
5530+
rss_change->after = (info2.vmrss + info2.vmswap) * K;
5531+
} else {
5532+
rss_change->after = rss_change->before = SIZE_MAX;
5533+
}
5534+
}
5535+
5536+
return true;
5537+
#else
5538+
return false; // musl
5539+
#endif
5540+
}

src/hotspot/os/linux/os_linux.inline.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,13 @@ inline bool os::must_commit_stack_guard_pages() {
4343
inline void os::map_stack_shadow_pages(address sp) {
4444
}
4545

46+
// Trim-native support
47+
inline bool os::can_trim_native_heap() {
48+
#ifdef __GLIBC__
49+
return true;
50+
#else
51+
return false; // musl
52+
#endif
53+
}
54+
4655
#endif // OS_LINUX_OS_LINUX_INLINE_HPP
Lines changed: 19 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
2-
* Copyright (c) 2021 SAP SE. All rights reserved.
3-
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2022 SAP SE. All rights reserved.
3+
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
44
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55
*
66
* This code is free software; you can redistribute it and/or modify it
@@ -24,56 +24,29 @@
2424
*/
2525

2626
#include "precompiled.hpp"
27-
#include "logging/log.hpp"
28-
#include "runtime/os.hpp"
27+
#include "runtime/os.inline.hpp"
28+
#include "trimCHeapDCmd.hpp"
2929
#include "utilities/debug.hpp"
30+
#include "utilities/globalDefinitions.hpp"
3031
#include "utilities/ostream.hpp"
31-
#include "trimCHeapDCmd.hpp"
3232

3333
#include <malloc.h>
3434

3535
void TrimCLibcHeapDCmd::execute(DCmdSource source, TRAPS) {
36-
#ifdef __GLIBC__
37-
stringStream ss_report(1024); // Note: before calling trim
38-
39-
os::Linux::meminfo_t info1;
40-
os::Linux::meminfo_t info2;
41-
// Query memory before...
42-
bool have_info1 = os::Linux::query_process_memory_info(&info1);
43-
44-
_output->print_cr("Attempting trim...");
45-
::malloc_trim(0);
46-
_output->print_cr("Done.");
47-
48-
// ...and after trim.
49-
bool have_info2 = os::Linux::query_process_memory_info(&info2);
50-
51-
// Print report both to output stream as well to UL
52-
bool wrote_something = false;
53-
if (have_info1 && have_info2) {
54-
if (info1.vmsize != -1 && info2.vmsize != -1) {
55-
ss_report.print_cr("Virtual size before: " SSIZE_FORMAT "k, after: " SSIZE_FORMAT "k, (" SSIZE_FORMAT "k)",
56-
info1.vmsize, info2.vmsize, (info2.vmsize - info1.vmsize));
57-
wrote_something = true;
58-
}
59-
if (info1.vmrss != -1 && info2.vmrss != -1) {
60-
ss_report.print_cr("RSS before: " SSIZE_FORMAT "k, after: " SSIZE_FORMAT "k, (" SSIZE_FORMAT "k)",
61-
info1.vmrss, info2.vmrss, (info2.vmrss - info1.vmrss));
62-
wrote_something = true;
63-
}
64-
if (info1.vmswap != -1 && info2.vmswap != -1) {
65-
ss_report.print_cr("Swap before: " SSIZE_FORMAT "k, after: " SSIZE_FORMAT "k, (" SSIZE_FORMAT "k)",
66-
info1.vmswap, info2.vmswap, (info2.vmswap - info1.vmswap));
67-
wrote_something = true;
36+
if (os::can_trim_native_heap()) {
37+
os::size_change_t sc;
38+
if (os::trim_native_heap(&sc)) {
39+
_output->print("Trim native heap: ");
40+
if (sc.after != SIZE_MAX) {
41+
const size_t delta = sc.after < sc.before ? (sc.before - sc.after) : (sc.after - sc.before);
42+
const char sign = sc.after < sc.before ? '-' : '+';
43+
_output->print_cr("RSS+Swap: " PROPERFMT "->" PROPERFMT " (%c" PROPERFMT ")",
44+
PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), sign, PROPERFMTARGS(delta));
45+
} else {
46+
_output->print_cr("(no details available).");
47+
}
6848
}
49+
} else {
50+
_output->print_cr("Not available.");
6951
}
70-
if (!wrote_something) {
71-
ss_report.print_raw("No details available.");
72-
}
73-
74-
_output->print_raw(ss_report.base());
75-
log_info(os)("malloc_trim:\n%s", ss_report.base());
76-
#else
77-
_output->print_cr("Not available.");
78-
#endif
7952
}

src/hotspot/os/windows/os_windows.inline.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,8 @@ inline void os::PlatformMonitor::notify_all() {
9393
WakeAllConditionVariable(&_cond);
9494
}
9595

96+
// stubbed-out trim-native support
97+
inline bool os::can_trim_native_heap() { return false; }
98+
inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; }
99+
96100
#endif // OS_WINDOWS_OS_WINDOWS_INLINE_HPP

src/hotspot/share/runtime/os.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,15 @@ class os: AllStatic {
366366
static bool uncommit_memory(char* addr, size_t bytes, bool executable = false);
367367
static bool release_memory(char* addr, size_t bytes);
368368

369+
// Does the platform support trimming the native heap?
370+
static bool can_trim_native_heap();
371+
372+
// Trim the C-heap. Optionally returns working set size change (RSS+Swap) in *rss_change.
373+
// Note: If trimming succeeded but no size change information could be obtained,
374+
// rss_change.after will contain SIZE_MAX upon return.
375+
struct size_change_t { size_t before; size_t after; };
376+
static bool trim_native_heap(size_change_t* rss_change = nullptr);
377+
369378
// A diagnostic function to print memory mappings in the given range.
370379
static void print_memory_mappings(char* addr, size_t bytes, outputStream* st);
371380
// Prints all mappings

src/hotspot/share/utilities/globalDefinitions.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,9 @@ inline T byte_size_in_proper_unit(T s) {
324324
}
325325
}
326326

327+
#define PROPERFMT SIZE_FORMAT "%s"
328+
#define PROPERFMTARGS(s) byte_size_in_proper_unit(s), proper_unit_for_byte_size(s)
329+
327330
inline const char* exact_unit_for_byte_size(size_t s) {
328331
#ifdef _LP64
329332
if (s >= G && (s % G) == 0) {

test/hotspot/gtest/runtime/test_os.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
#include "precompiled.hpp"
2525
#include "memory/allocation.hpp"
2626
#include "memory/resourceArea.hpp"
27-
#include "runtime/os.hpp"
27+
#include "runtime/os.inline.hpp"
2828
#include "runtime/thread.hpp"
2929
#include "services/memTracker.hpp"
3030
#include "utilities/globalDefinitions.hpp"
@@ -876,3 +876,27 @@ TEST_VM(os, is_first_C_frame) {
876876
EXPECT_FALSE(os::is_first_C_frame(&cur_frame));
877877
#endif // _WIN32
878878
}
879+
880+
#ifdef __GLIBC__
881+
TEST_VM(os, trim_native_heap) {
882+
EXPECT_TRUE(os::can_trim_native_heap());
883+
os::size_change_t sc;
884+
sc.before = sc.after = (size_t)-1;
885+
EXPECT_TRUE(os::trim_native_heap(&sc));
886+
tty->print_cr(SIZE_FORMAT "->" SIZE_FORMAT, sc.before, sc.after);
887+
// Regardless of whether we freed memory, both before and after
888+
// should be somewhat believable numbers (RSS).
889+
const size_t min = 5 * M;
890+
const size_t max = LP64_ONLY(20 * G) NOT_LP64(3 * G);
891+
ASSERT_LE(min, sc.before);
892+
ASSERT_GT(max, sc.before);
893+
ASSERT_LE(min, sc.after);
894+
ASSERT_GT(max, sc.after);
895+
// Should also work
896+
EXPECT_TRUE(os::trim_native_heap());
897+
}
898+
#else
899+
TEST_VM(os, trim_native_heap) {
900+
EXPECT_FALSE(os::can_trim_native_heap());
901+
}
902+
#endif // __GLIBC__

test/hotspot/jtreg/serviceability/dcmd/vm/TrimLibcHeapTest.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
* @test
3232
* @summary Test of diagnostic command VM.trim_libc_heap
3333
* @library /test/lib
34-
* @requires os.family == "linux"
34+
* @requires (os.family=="linux") & !vm.musl
3535
* @modules java.base/jdk.internal.misc
3636
* java.compiler
3737
* java.management
@@ -42,10 +42,7 @@ public class TrimLibcHeapTest {
4242
public void run(CommandExecutor executor) {
4343
OutputAnalyzer output = executor.execute("System.trim_native_heap");
4444
output.reportDiagnosticSummary();
45-
output.shouldMatch("(Done|Not available)"); // Not available could happen on Linux + non-glibc (eg. muslc)
46-
if (output.firstMatch("Done") != null) {
47-
output.shouldMatch("(Virtual size before|RSS before|Swap before|No details available)");
48-
}
45+
output.shouldMatch(".*Trim native heap: RSS\\+Swap: \\d+[BKM]->\\d+[BKM].*");
4946
}
5047

5148
@Test

0 commit comments

Comments
 (0)