diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -108,6 +108,9 @@ # include # include # include +#ifdef __GLIBC__ +# include +#endif #ifndef _GNU_SOURCE #define _GNU_SOURCE @@ -2108,7 +2111,10 @@ os::Posix::print_load_average(st); - os::Linux::print_full_memory_info(st); + os::Linux::print_system_memory_info(st); + st->cr(); + + os::Linux::print_process_memory_info(st); os::Linux::print_proc_sys_info(st); @@ -2262,7 +2268,7 @@ "/proc/sys/kernel/pid_max", st); } -void os::Linux::print_full_memory_info(outputStream* st) { +void os::Linux::print_system_memory_info(outputStream* st) { _print_ascii_file_h("\n/proc/meminfo", "/proc/meminfo", st); st->cr(); @@ -2274,6 +2280,63 @@ "/sys/kernel/mm/transparent_hugepage/defrag", st); } +void os::Linux::print_process_memory_info(outputStream* st) { + + st->print_cr("Process Memory:"); + + // Print virtual and resident set size; peak values; swap; and for + // rss its components if the kernel is recent enough. + ssize_t vmsize = -1, vmpeak = -1, vmswap = -1, + vmrss = -1, vmhwm = -1, rssanon = -1, rssfile = -1, rssshmem = -1; + const int num_values = 8; + int num_found = 0; + FILE* f = ::fopen("/proc/self/status", "r"); + char buf[256]; + while (::fgets(buf, sizeof(buf), f) != NULL && num_found < num_values) { + if ( (vmsize == -1 && sscanf(buf, "VmSize: " SSIZE_FORMAT " kB", &vmsize) == 1) || + (vmpeak == -1 && sscanf(buf, "VmPeak: " SSIZE_FORMAT " kB", &vmpeak) == 1) || + (vmswap == -1 && sscanf(buf, "VmSwap: " SSIZE_FORMAT " kB", &vmswap) == 1) || + (vmhwm == -1 && sscanf(buf, "VmHWM: " SSIZE_FORMAT " kB", &vmhwm) == 1) || + (vmrss == -1 && sscanf(buf, "VmRSS: " SSIZE_FORMAT " kB", &vmrss) == 1) || + (rssanon == -1 && sscanf(buf, "RssAnon: " SSIZE_FORMAT " kB", &rssanon) == 1) || + (rssfile == -1 && sscanf(buf, "RssFile: " SSIZE_FORMAT " kB", &rssfile) == 1) || + (rssshmem == -1 && sscanf(buf, "RssShmem: " SSIZE_FORMAT " kB", &rssshmem) == 1) + ) + { + num_found ++; + } + } + st->print_cr("Virtual Size: " SSIZE_FORMAT "K (peak: " SSIZE_FORMAT "K)", vmsize, vmpeak); + st->print("Resident Set Size: " SSIZE_FORMAT "K (peak: " SSIZE_FORMAT "K)", vmrss, vmhwm); + if (rssanon != -1) { // requires kernel >= 4.5 + st->print(" (anon: " SSIZE_FORMAT "K, file: " SSIZE_FORMAT "K, shmem: " SSIZE_FORMAT "K)", + rssanon, rssfile, rssshmem); + } + st->cr(); + if (vmswap != -1) { // requires kernel >= 2.6.34 + st->print_cr("Swapped out: " SSIZE_FORMAT "K", vmswap); + } + + // Print glibc outstanding allocations. + // (note: there is no implementation of mallinfo for muslc) +#ifdef __GLIBC__ + struct mallinfo mi = ::mallinfo(); + + // 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. + const size_t total_allocated = (size_t)(unsigned)mi.uordblks; + st->print("C-Heap outstanding allocations: " SIZE_FORMAT "K", total_allocated / K); + // Since mallinfo members are int, glibc values may have wrapped. Warn about this. + if ((vmrss * K) > UINT_MAX && (vmrss * K) > (total_allocated + UINT_MAX)) { + st->print(" (may have wrapped)"); + } + st->cr(); + +#endif // __GLIBC__ + +} + void os::Linux::print_ld_preload_file(outputStream* st) { _print_ascii_file("/etc/ld.so.preload", st, "\n/etc/ld.so.preload:"); st->cr(); diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -107,7 +107,8 @@ static bool release_memory_special_shm(char* base, size_t bytes); static bool release_memory_special_huge_tlbfs(char* base, size_t bytes); - static void print_full_memory_info(outputStream* st); + static void print_process_memory_info(outputStream* st); + static void print_system_memory_info(outputStream* st); static void print_container_info(outputStream* st); static void print_steal_info(outputStream* st); static void print_distro_info(outputStream* st);