Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/hotspot/os/aix/os_aix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2716,5 +2716,8 @@ void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {}
#if INCLUDE_JFR

void os::jfr_report_memory_info() {}
void os::jfr_report_process_size() {}
void os::jfr_report_libc_statistics() {}
int os::num_process_threads() { return -1; }

#endif // INCLUDE_JFR
4 changes: 2 additions & 2 deletions src/hotspot/os/aix/os_aix.inline.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2018 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
Expand Down Expand Up @@ -54,6 +54,6 @@ inline void os::map_stack_shadow_pages(address sp) {

// Trim-native support, stubbed out for now, may be enabled later
inline bool os::can_trim_native_heap() { return false; }
inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; }
inline bool os::trim_native_heap(os::size_change_t& rss_change) { return false; }

#endif // OS_AIX_OS_AIX_INLINE_HPP
82 changes: 57 additions & 25 deletions src/hotspot/os/bsd/os_bsd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,20 +207,32 @@ julong os::physical_memory() {
return Bsd::physical_memory();
}

size_t os::rss() {
size_t rss = 0;
#ifdef __APPLE__
bool os::Bsd::query_process_memory_info(os::Bsd::process_info_t* pi) {
mach_task_basic_info info;
mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT;

kern_return_t ret = task_info(mach_task_self(), MACH_TASK_BASIC_INFO,
(task_info_t)&info, &count);
if (ret == KERN_SUCCESS) {
rss = info.resident_size;
pi->vsize = info.virtual_size;
pi->rss = info.resident_size;
// We've seen that resident_size_max sometimes trails resident_size with one page.
// Make sure we always report size <= peak
pi->rssmax = MAX2(info.resident_size_max, info.resident_size);
return true;
}
#endif // __APPLE__
return false;
}
#endif

return rss;
size_t os::rss() {
#ifdef __APPLE__
os::Bsd::process_info_t info;
if (os::Bsd::query_process_memory_info(&info)) {
return info.rss;
}
#endif // __APPLE__
return 0;
}

// Cpu architecture string
Expand Down Expand Up @@ -2447,32 +2459,52 @@ void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {}

#if INCLUDE_JFR

void os::jfr_report_memory_info() {
#ifdef __APPLE__
mach_task_basic_info info;
mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT;
#define JFR_WARN_ONCE(text) { \
static bool first_warning = true; \
if (first_warning) { \
log_warning(jfr)(text); \
first_warning = false; \
} \
}

kern_return_t ret = task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &count);
if (ret == KERN_SUCCESS) {
// Send the RSS JFR event
#ifdef __APPLE__
void os::jfr_report_memory_info() {
os::Bsd::process_info_t info;
if (os::Bsd::query_process_memory_info(&info)) {
EventResidentSetSize event;
event.set_size(info.resident_size);
// We've seen that resident_size_max sometimes trails resident_size with one page.
// Make sure we always report size <= peak
event.set_peak(MAX2(info.resident_size_max, info.resident_size));
event.set_size(info.rss);
event.set_peak(info.rssmax);
event.commit();
} else {
// Log a warning
static bool first_warning = true;
if (first_warning) {
log_warning(jfr)("Error fetching RSS values: task_info failed");
first_warning = false;
}
JFR_WARN_ONCE("Error fetching RSS values: task_info failed");
}
}

void os::jfr_report_process_size() {
os::Bsd::process_info_t info;
if (os::Bsd::query_process_memory_info(&info)) {
EventProcessSize e;
e.set_vsize(info.vsize);
e.set_rss(info.rss);
e.set_rssPeak(info.rssmax);
e.set_rssAnon(0);
e.set_rssFile(0);
e.set_rssShmem(0);
e.set_committed(0);
e.set_pagetable(0);
e.set_swap(0);
e.commit();
} else {
JFR_WARN_ONCE("Error fetching RSS values: task_info failed");
}

#endif // __APPLE__
}
#else
void os::jfr_report_memory_info() {}
void os::jfr_report_process_size() {}
#endif // __APPLE__

void os::jfr_report_libc_statistics() {}
int os::num_process_threads() { return -1; }
#endif // INCLUDE_JFR

bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) {
Expand Down
13 changes: 12 additions & 1 deletion src/hotspot/os/bsd/os_bsd.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2025, 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
Expand Down Expand Up @@ -36,6 +36,17 @@ class os::Bsd {
// mach_absolute_time
static mach_timebase_info_data_t _timebase_info;
static volatile uint64_t _max_abstime;

// Output structure for query_process_memory_info()
struct process_info_t {
// see mach_task_basic_info_data_t
size_t vsize; // current virtual size
size_t rss; // current resident set size
size_t rssmax; // max resident set size
};

// Attempts to query memory information about the current process and return it in the output structure.
static bool query_process_memory_info(process_info_t* info);
#endif

static GrowableArray<int>* _cpu_to_node;
Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/os/bsd/os_bsd.inline.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2025, 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
Expand Down Expand Up @@ -57,6 +57,6 @@ inline void os::map_stack_shadow_pages(address sp) {

// Trim-native support, stubbed out for now, may be enabled later
inline bool os::can_trim_native_heap() { return false; }
inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; }
inline bool os::trim_native_heap(os::size_change_t& rss_change) { return false; }

#endif // OS_BSD_OS_BSD_INLINE_HPP
125 changes: 89 additions & 36 deletions src/hotspot/os/linux/os_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,8 +351,8 @@ julong os::physical_memory() {

size_t os::rss() {
size_t size = 0;
os::Linux::meminfo_t info;
if (os::Linux::query_process_memory_info(&info)) {
os::Linux::process_info_t info;
if (os::Linux::query_process_info(&info)) {
size = info.vmrss * K;
}
return size;
Expand Down Expand Up @@ -2313,13 +2313,14 @@ void os::Linux::print_system_memory_info(outputStream* st) {
"/sys/kernel/mm/transparent_hugepage/defrag", st);
}

bool os::Linux::query_process_memory_info(os::Linux::meminfo_t* info) {
bool os::Linux::query_process_info(os::Linux::process_info_t* info) {
FILE* f = os::fopen("/proc/self/status", "r");
const int num_values = sizeof(os::Linux::meminfo_t) / sizeof(size_t);
int num_found = 0;
char buf[256];
info->vmsize = info->vmpeak = info->vmrss = info->vmhwm = info->vmswap =
info->rssanon = info->rssfile = info->rssshmem = -1;
info->rssanon = info->rssfile = info->rssshmem = info->vmpte = -1;
info->threads = info->fdsize = -1;
constexpr int num_values = 11;
int num_found = 0;
if (f != nullptr) {
while (::fgets(buf, sizeof(buf), f) != nullptr && num_found < num_values) {
if ( (info->vmsize == -1 && sscanf(buf, "VmSize: %zd kB", &info->vmsize) == 1) ||
Expand All @@ -2329,7 +2330,10 @@ bool os::Linux::query_process_memory_info(os::Linux::meminfo_t* info) {
(info->vmrss == -1 && sscanf(buf, "VmRSS: %zd kB", &info->vmrss) == 1) ||
(info->rssanon == -1 && sscanf(buf, "RssAnon: %zd kB", &info->rssanon) == 1) || // Needs Linux 4.5
(info->rssfile == -1 && sscanf(buf, "RssFile: %zd kB", &info->rssfile) == 1) || // Needs Linux 4.5
(info->rssshmem == -1 && sscanf(buf, "RssShmem: %zd kB", &info->rssshmem) == 1) // Needs Linux 4.5
(info->rssshmem == -1 && sscanf(buf, "RssShmem: %zd kB", &info->rssshmem) == 1) || // Needs Linux 4.5
(info->vmpte == -1 && sscanf(buf, "VmPTE: %zd kB", &info->vmpte) == 1) || // Needs Linux 2.6.10
(info->fdsize == -1 && sscanf(buf, "FDSize: %d", &info->fdsize) == 1) ||
(info->threads == -1 && sscanf(buf, "Threads: %d", &info->threads) == 1)
)
{
num_found ++;
Expand Down Expand Up @@ -2375,8 +2379,8 @@ void os::Linux::print_process_memory_info(outputStream* st) {

// Print virtual and resident set size; peak values; swap; and for
// rss its components if the kernel is recent enough.
meminfo_t info;
if (query_process_memory_info(&info)) {
process_info_t info;
if (query_process_info(&info)) {
st->print_cr("Virtual Size: %zdK (peak: %zdK)", info.vmsize, info.vmpeak);
st->print("Resident Set Size: %zdK (peak: %zdK)", info.vmrss, info.vmhwm);
if (info.rssanon != -1) { // requires kernel >= 4.5
Expand Down Expand Up @@ -2660,26 +2664,73 @@ void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {

#if INCLUDE_JFR

#define JFR_WARN_ONCE(text) { \
static bool first_warning = true; \
if (first_warning) { \
log_warning(jfr)(text); \
first_warning = false; \
} \
}

void os::jfr_report_memory_info() {
os::Linux::meminfo_t info;
if (os::Linux::query_process_memory_info(&info)) {
os::Linux::process_info_t info;
if (os::Linux::query_process_info(&info)) {
// Send the RSS JFR event
EventResidentSetSize event;
event.set_size(info.vmrss * K);
event.set_peak(info.vmhwm * K);
event.commit();
} else {
// Log a warning
static bool first_warning = true;
if (first_warning) {
log_warning(jfr)("Error fetching RSS values: query_process_memory_info failed");
first_warning = false;
}
JFR_WARN_ONCE("Error fetching RSS values: query_process_memory_info failed");
}
}

void os::jfr_report_process_size() {
os::Linux::process_info_t info;
if (os::Linux::query_process_info(&info)) {
EventProcessSize e;
e.set_vsize(info.vmsize * K);
e.set_rss(info.vmrss * K);
e.set_rssPeak(info.vmhwm * K);
e.set_rssAnon(info.rssanon * K);
e.set_rssFile(info.rssfile * K);
e.set_rssShmem(info.rssshmem * K);
e.set_committed(0);
e.set_pagetable(info.vmpte * K);
e.set_swap(info.vmswap * K);
e.commit();
} else {
JFR_WARN_ONCE("Error fetching ProcessSize: query_process_memory_info failed");
}
}

void os::jfr_report_libc_statistics() {
#ifdef __GLIBC__
bool might_have_wrapped = false;
os::Linux::glibc_mallinfo mi;
os::Linux::get_mallinfo(&mi, &might_have_wrapped);
if (!might_have_wrapped) {
EventLibcStatistics e;
e.set_mallocOutstanding(mi.uordblks + mi.hblkhd);
e.set_mallocRetained(mi.fordblks);
e.set_trims(mi.num_trims);
e.commit();
} else {
JFR_WARN_ONCE("Error libc statistics: too old glibc");
}
#endif
}

#endif // INCLUDE_JFR

int os::num_process_threads() {
os::Linux::process_info_t info;
if (os::Linux::query_process_info(&info)) {
return info.threads; // These are OS threads
}
return -1;
}

#if defined(AMD64) || defined(IA32) || defined(X32)
const char* search_string = "model name";
#elif defined(M68K)
Expand Down Expand Up @@ -4872,8 +4923,9 @@ int os::open(const char *path, int oflag, int mode) {
// All file descriptors that are opened in the Java process and not
// specifically destined for a subprocess should have the close-on-exec
// flag set. If we don't set it, then careless 3rd party native code
// might fork and exec without closing all appropriate file descriptors,
// and this in turn might:
// might fork and exec without closing all appropriate file descriptors
// (e.g. as we do in closeDescriptors in UNIXProcess.c), and this in
// turn might:
//
// - cause end-of-file to fail to be detected on some file
// descriptors, resulting in mysterious hangs, or
Expand Down Expand Up @@ -5308,6 +5360,7 @@ void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {
}

#ifdef __GLIBC__
static unsigned g_num_trims = 0;
void os::Linux::get_mallinfo(glibc_mallinfo* out, bool* might_have_wrapped) {
if (g_mallinfo2) {
new_mallinfo mi = g_mallinfo2();
Expand All @@ -5321,6 +5374,7 @@ void os::Linux::get_mallinfo(glibc_mallinfo* out, bool* might_have_wrapped) {
out->uordblks = mi.uordblks;
out->fordblks = mi.fordblks;
out->keepcost = mi.keepcost;
out->num_trims = g_num_trims;
*might_have_wrapped = false;
} else if (g_mallinfo) {
old_mallinfo mi = g_mallinfo();
Expand All @@ -5335,6 +5389,7 @@ void os::Linux::get_mallinfo(glibc_mallinfo* out, bool* might_have_wrapped) {
out->uordblks = (size_t)(unsigned)mi.uordblks;
out->fordblks = (size_t)(unsigned)mi.fordblks;
out->keepcost = (size_t)(unsigned)mi.keepcost;
out->num_trims = g_num_trims;
*might_have_wrapped = NOT_LP64(false) LP64_ONLY(true);
} else {
// We should have either mallinfo or mallinfo2
Expand All @@ -5350,29 +5405,27 @@ int os::Linux::malloc_info(FILE* stream) {
}
#endif // __GLIBC__

bool os::trim_native_heap(os::size_change_t* rss_change) {
bool os::trim_native_heap(os::size_change_t& rss_change) {
#ifdef __GLIBC__
os::Linux::meminfo_t info1;
os::Linux::meminfo_t info2;
os::Linux::process_info_t info1;
os::Linux::process_info_t info2;

bool have_info1 = rss_change != nullptr &&
os::Linux::query_process_memory_info(&info1);
bool have_info1 = os::Linux::query_process_info(&info1);
::malloc_trim(0);
bool have_info2 = rss_change != nullptr && have_info1 &&
os::Linux::query_process_memory_info(&info2);
bool have_info2 = have_info1 && os::Linux::query_process_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;
}
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;
}

g_num_trims ++;

return true;
#else
return false; // musl
Expand Down
Loading