-
Enhancement
-
Resolution: Unresolved
-
P4
-
11, 17, 21, 22
-
Fix Understood
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
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 "
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
- is blocked by
-
JDK-8317453 NMT: Performance benchmarks are needed to measure speed and memory
- In Progress
- relates to
-
JDK-8199133 [BACKOUT] NMT: Enhance thread stack tracking
- Resolved
-
JDK-8199067 [REDO] NMT: Enhance thread stack tracking
- Closed
-
JDK-8191369 NMT: Enhance thread stack tracking
- Resolved
-
JDK-8301749 Tracking malloc pooled memory size
- Resolved
-
JDK-8313083 Print 'rss' and 'cache' as part of the container information
- Resolved
(1 relates to)