Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8249666

Improve Native Memory Tracking to report the actual RSS usage

XMLWordPrintable

    • Fix Understood

      Update 2025-04-8:

      The goal of the ticket is to provide the live memory size of mmap sections registered with NMT when reporting NMT mmap information. That should be a third number, alongside reserved and committed.

      Obviously, this number has to be queried in real-time, at the time when the report is done. Since that may take a bit, we can make the option to show live memory optional by guarding it behind a jcmd flag. The information would be stale after the report finishes, so there is no need to store it long-term.

      I don't think we need this information in *detail* reports, just in summary. Since detail reports are kept on a per-commit base and live memory does not correlate well to committing memory, that would not be very useful.

      Note that this feature already exists in `System.map` since JDK-8322475, and not only for NMT-tracked VMAs, but for all VMAs of the process. The command is also reasonably fast. So, the base problem is already solved; this same path could be taken (maybe reusing/revamping the original code).

      ----

      Original issue text:

      Currently, NMT shows allocated memory as either "Reserved" or "Committed". Reserved memory is actually just reserved, virtual address space which was mmaped with MAP_NORESERVE, while Committed memory is mapped without MAP_NORESERVE. In the output of top or pmap, both Reserved and Committed show up as "Virtual" memory until they will be used for the first time (i.e. touched). Only after a memory page (usually 4k) has been written to for the first time, it will consume physical memory and appear in the "resident set" (i.e. RSS) of top's/pmap's output.

      The difference between allocating memory with or without MAP_NORESERVE depends on the Linux memory overcommit configuration [1]. By default, overcommit is allowed and memory allocated with MAP_NORESERVE isn't checked against the available physical memory (see man proc(5) [2]). If the HotSpot VM tries to commit reserved memory (i.e. re-map a memory region without MAP_NORESERVE which was previously mapped with MAP_NORESERVE) and there's not enough free memory available an OutOfMemoyError will be thrown.

      But even committing a memory region doesn't mean that physical memory pages will be allocated for that region (and accounted in the processes RSS) until that memory will be written to for the first time. So depending on the overcommit settings, an application might still crash with a SIGBUS because it is running out of physical memory when touching memory for the first time which was committed a long time ago.

      The main problem with the current NMT output is that it can not distinguish between touched and untouched Committed memory. If a VM is started with -Xms1g -Xmx1g the VM will commit the whole 1g heap and NMT will report Reserved=Committed=1g. In contrast, system tools like ps/top will only show the part of the heap as RSS which has really been used (i.e. touched), usually just about 100m. This is at least confusing.

      But we can do better. We can use mincore() [3] to find the RSS part of the amount of memory which is accounted as Committed in NMT's output and report that instead (or in addition). Notice that this feature has already been implemented for threads stacks with "JDK-8191369: NMT: Enhance thread stack tracking" [4] and just needs to be extended to all other kinds of memory, starting with the Java heap.

      Alternatively, instead of using mincore() we could use the information from /proc/<pid>/smaps (also accessible through the pmap [5] command line utility) directly and merge it with the NMT data to get a complete, annotated overview of the whole address space of a Java process.

      [1] https://www.kernel.org/doc/Documentation/vm/overcommit-accounting
      [2] https://man7.org/linux/man-pages/man5/proc.5.html
      [3] https://man7.org/linux/man-pages/man2/mincore.2.html
      [4] https://bugs.openjdk.java.net/browse/JDK-8191369
      [5] https://man7.org/linux/man-pages/man1/pmap.1.html

            stuefe Thomas Stuefe
            simonis Volker Simonis
            Votes:
            2 Vote for this issue
            Watchers:
            11 Start watching this issue

              Created:
              Updated: