diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index d7bc524e75b..3d44d839735 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -370,11 +370,20 @@ size_t os::physical_memory() { return phys_mem; } +// Returns the resident set size (RSS) of the process. +// Falls back to using VmRSS from /proc/self/status if /proc/self/smaps_rollup is unavailable. +// Note: On kernels with memory cgroups or shared memory, VmRSS may underreport RSS. +// Users requiring accurate RSS values should be aware of this limitation. size_t os::rss() { size_t size = 0; - os::Linux::meminfo_t info; - if (os::Linux::query_process_memory_info(&info)) { - size = info.vmrss * K; + os::Linux::accurate_meminfo_t accurate_info; + if (os::Linux::query_accurate_process_memory_info(&accurate_info) && accurate_info.rss != -1) { + size = accurate_info.rss * K; + } else { + os::Linux::meminfo_t info; + if (os::Linux::query_process_memory_info(&info)) { + size = info.vmrss * K; + } } return size; } @@ -2362,6 +2371,37 @@ bool os::Linux::query_process_memory_info(os::Linux::meminfo_t* info) { return false; } +// Accurate memory information need Linux 4.14 or newer +bool os::Linux::query_accurate_process_memory_info(os::Linux::accurate_meminfo_t* info) { + FILE* f = os::fopen("/proc/self/smaps_rollup", "r"); + if (f == nullptr) { + return false; + } + + const size_t num_values = sizeof(os::Linux::accurate_meminfo_t) / sizeof(size_t); + size_t num_found = 0; + char buf[256]; + info->rss = info->pss = info->pssdirty = info->pssanon = + info->pssfile = info->pssshmem = info->swap = info->swappss = -1; + + while (::fgets(buf, sizeof(buf), f) != nullptr && num_found < num_values) { + if ( (info->rss == -1 && sscanf(buf, "Rss: %zd kB", &info->rss) == 1) || + (info->pss == -1 && sscanf(buf, "Pss: %zd kB", &info->pss) == 1) || + (info->pssdirty == -1 && sscanf(buf, "Pss_Dirty: %zd kB", &info->pssdirty) == 1) || + (info->pssanon == -1 && sscanf(buf, "Pss_Anon: %zd kB", &info->pssanon) == 1) || + (info->pssfile == -1 && sscanf(buf, "Pss_File: %zd kB", &info->pssfile) == 1) || + (info->pssshmem == -1 && sscanf(buf, "Pss_Shmem: %zd kB", &info->pssshmem) == 1) || + (info->swap == -1 && sscanf(buf, "Swap: %zd kB", &info->swap) == 1) || + (info->swappss == -1 && sscanf(buf, "SwapPss: %zd kB", &info->swappss) == 1) + ) + { + num_found ++; + } + } + fclose(f); + return true; +} + #ifdef __GLIBC__ // For Glibc, print a one-liner with the malloc tunables. // Most important and popular is MALLOC_ARENA_MAX, but we are diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp index d3e0d6c5668..497d383200d 100644 --- a/src/hotspot/os/linux/os_linux.hpp +++ b/src/hotspot/os/linux/os_linux.hpp @@ -181,6 +181,23 @@ class os::Linux { // fields will contain -1. static bool query_process_memory_info(meminfo_t* info); + // Output structure for query_accurate_process_memory_info() (all values in KB) + struct accurate_meminfo_t { + ssize_t rss; // current resident set size + ssize_t pss; // current proportional set size + ssize_t pssdirty; // proportional set size (dirty) + ssize_t pssanon; // proportional set size (anonymous mappings) + ssize_t pssfile; // proportional set size (file mappings) + ssize_t pssshmem; // proportional set size (shared mappings) + ssize_t swap; // swapped out + ssize_t swappss; // proportional set size (swapped out) + }; + + // Attempts to query accurate memory information from /proc/self/smaps_rollup and return it in the output structure. + // May fail (returns false) or succeed (returns true) but not all output fields are available; unavailable + // fields will contain -1. + static bool query_accurate_process_memory_info(accurate_meminfo_t* info); + // Tells if the user asked for transparent huge pages. static bool _thp_requested; diff --git a/test/hotspot/jtreg/gc/TestAlwaysPreTouchBehavior.java b/test/hotspot/jtreg/gc/TestAlwaysPreTouchBehavior.java index b8197f70384..141ef7ba197 100644 --- a/test/hotspot/jtreg/gc/TestAlwaysPreTouchBehavior.java +++ b/test/hotspot/jtreg/gc/TestAlwaysPreTouchBehavior.java @@ -155,7 +155,7 @@ public class TestAlwaysPreTouchBehavior { } if (available > requiredAvailable) { Asserts.assertGreaterThan(rss, minRequiredRss, "RSS of this process(" + rss + "b) should be bigger " + - "than or equal to heap size(" + heapSize + "b) (available memory: " + available + ")"); + "than or equal to heap size(" + heapSize + "b) (available memory: " + available + "). On Linux Kernel < 4.14 RSS can be inaccurate"); } } }