Summary
-------
Add Linux-specific jcmd to trim the native C-heap.
Problem
-------
When returning memory back to the glibc C-heap using `free(3)`, that memory is often retained instead of being returned to the Operating System. The glibc is somewhat notorious for this behavior, whereas other libc-implementations release memory more promptly. This effect depends on allocation pattern, but usually the finer granular allocations are, the more pronounced is this effect. As a result the JVM process could experience permanent increases in working set size due to temporary spikes in C-heap usage.
Beside the obvious disadvantage of using too much memory it also confuses support engineers: faced with a JVM showing a high working set size, they cannot know if that footprint is really memory used by this process, or if part of that memory consists of unused glibc C-heap. Even though they can see how much C-heap the JVM thinks it uses (using NMT - and beware the sometimes considerable glibc-overhead), if NMT does not show anything untoward nothing is answered.
Solution
--------
A new Linux-specific command is introduced to the jcmd command collection. That command would trigger a call to `malloc_trim(3)` call inside the JVM process when running on glibc. In the future this could be expanded to other `libc` environments if needed and if they provide a suitable API.
`malloc_trim(3)` is a glibc-specific API to explicitly trim its C-heap [1]. When this API is called, the glibc attempts to reduce the C-heap footprint by shrinking the process heap (decreasing the brk) and discard dirty unneeded pages using `madvise(2)`. This usually has immediate effect and releases superfluous memory to the Operating System.
Being able to manually trigger `malloc_trim(3)` would have the following advantages:
- obviously it reduces memory pressure as a stop gap measure
- when analyzing cases of high memory footprint, it would allow to distinguish "real" footprint from cases where the glibc just holds on to memory. This is especially important for cases where the C-heap spike was used by code outside the JVM itself and therefore does not show up on NMT.
Specification
-------------
The proposed command takes the form:
`jcmd System.trim_native_heap`
and has no arguments.
Description: Attempts to free up memory by trimming the native C-heap
When running under glibc, calling it would cause `malloc_trim(3)` to be executed synchronously. `jcmd` will wait for the trim to finish and return with information about how much memory had been freed by this operation.
When running on non-glibc platforms (e.g. with muslc on Alpine), the command prints "Not available".
For example:
```
thomas@starfish:~$ jcmd 18770 System.trim_native_heap
18770:
Attempting trim...
Done.
Virtual size before: 28849744k, after: 28849724k, (-20k)
RSS before: 8685896k, after: 920740k, (-7765156k) <<<<
Swap before: 0k, after: 0k, (0k)
```
A preliminary RFR (which may be adapted depending on the outcome of this CSR) can be found here: [4]
[1] https://man7.org/linux/man-pages/man3/malloc_trim.3.html
[2] https://bugs.ruby-lang.org/issues/15667
[3] https://github.com/openjdk/jdk/pull/4510#issuecomment-864762379
[4] https://github.com/openjdk/jdk/pull/4510