[RFC 8285277] - How should the JVM handle container memory limits
Severin Gehwolf
sgehwolf at redhat.com
Thu Apr 21 09:49:52 UTC 2022
On Wed, 2022-04-20 at 11:09 -0700, Ioi Lam wrote:
> I would like to have a discussion on how (or whether) the JVM should
> handle container memory limits -- see JDK-8285277 [1]
It does handle container memory limits. os::physical_memory() returns
the container limit instead of the host value if a container limit is
in place. That was one big aspect of JDK-8146115 when it was done in
JDK 10 timeframe. See:
https://github.com/openjdk/jdk/blob/fa04d1f832ff201248f935939fa255988053a1d0/src/hotspot/os/linux/os_linux.cpp
#L217..L232
What am I missing?
> The JVM may be terminated by the Linux OOM killer if it tries to use
> more memory than the memory limit specified for a container. JDK-8284900
> [2] tries to avoid OOM by checking InitialHeapSize against the memory
> limit. However, this is incomplete because the JVM can use memory in
> other ways:
>
> - If -Xmx is larger than -Xms, the heap may expand
> - malloc memory
> - code cache
> - thread stacks
JDK-8284900 is somewhat a special case which, IIUIC, tries to avoid
user-errors detectable at JVM startup. For example setting -Xms to a
value >= physical memory (including swap). In this case the JVM would
be at risk to get killed by the OOM killer and doing this check on
start-up would catch it before it comes to it.
On the other hand, I don't see any handling of such a case on a
*physical* machine. Consider a machine with 8GB of RAM and somebody
spawning a JVM with -Xms8g on it. It'll happily oblige? In one of my
VMs with 8GB I see this:
$ ./jdk19-jdk/bin/java -Xms8g -XX:+PrintFlagsFinal -version 2>&1 | grep InitialHeapSize
size_t InitialHeapSize = 8589934592 {product} {command line}
$ free --giga
total used free shared buff/cache available
Mem: 8 0 7 0 0 7
Swap: 8 0 8
> We have several choices:
>
> (a) Following the direction of JDK-8284900, check for the initial memory
> usage of other types of memory as well. The problem with this is that
> checking the "initial" usage some type of memory usage (malloc or stack)
> is difficult or impossible.
>
> (b) Avoid committing more memory when the total memory usage is close to
> the limit. E.g., avoid expanding the Java heap, or return NULL from
> os::malloc(). The problem is that some operations in the VM cannot
> handle malloc failure and will terminate the VM anyway. Also, trying to
> obey the memory limit with concurrent allocator/deallocator threads is
> probably difficult or impossible.
>
> (c) Do not consider the memory limit and let the VM be killed by the OOM
> killer. This may be what the user wants -- the user knows that the app
> will normally run within the memory limit, so if the heap expands too
> much the app probably has a memory leak and should be killed, to be
> automatically restarted by an external mechanism (such as Kubernetes).
Neither of the above?
It would perhaps make sense to do some sanitiy checks on JVM start-up
(somewhat akin to JDK-8284900). But this should probably be done with
the main operating system API. Not using OSContainer API as proposed in
JDK-8284900. For example, print a warning if MaxHeapSize,
InitialHeapSize and MinHeapSize are larger than the reported physical
memory (and/or cap it at a lower size if so).
Isn't (b) being handled by setting os::pysical_memory() and
os::available_memory() to the container limits (which we currently do)?
It would behave similarly to a physical machine running out of memory,
no?
Thanks,
Severin
> [1] https://bugs.openjdk.java.net/browse/JDK-8285277
> [2] https://bugs.openjdk.java.net/browse/JDK-8284900
>
More information about the hotspot-dev
mailing list