JDK-8155004 : CrashOnOutOfMemoryError doesn't work for OOM caused by inability to create threads
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 8,9,11,15,16,17
  • Priority: P3
  • Status: Resolved
  • Resolution: Won't Fix
  • OS: linux
  • CPU: x86_64
  • Submitted: 2016-04-20
  • Updated: 2021-08-27
  • Resolved: 2021-04-21
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
Update 2021-04-20: this affects all ....OnOutOfMemoryError switches, not only CrashOnOutOfMemoryError.

--------------


FULL PRODUCT VERSION :
java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)

FULL OS VERSION :
Linux xxxxx 4.0.9 #1 SMP Fri Feb 26 15:21:14 PST 2016 x86_64 x86_64 x86_64 GNU/Linux
Darwin xxxxx 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05 PST 2016; root:xnu-3248.40.184~3/REL

A DESCRIPTION OF THE PROBLEM :
The newly introduced CrashOnOutOfMemoryError option doesn't appear to work when the cause of the OOM is due to not being able to create new threads.

THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: Did not try

THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Did not try

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the program below with "java -XX:+CrashOnOutOfMemoryError Test". After a few seconds, an OutOfMemoryError (unable to create new native thread) will be printed to the console but the program won't exit.

EXPECTED VERSUS ACTUAL BEHAVIOR :
I would expect the VM to crash, but it keeps running.
REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
class Test {
    public static void main(String[] args)
            throws InterruptedException
    {
        Thread t = new Thread(() -> {
            while (true) {
                new Thread(() -> {
                    try {
                        Thread.currentThread().join();
                    }
                    catch (InterruptedException e) {
                    }
                }).start();
            }
        });

        t.start();
        Thread.currentThread().join();
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Use a JVMTI agent to intercept ResourceExhausted events and forcibly exit the VM (e.g., https://github.com/airlift/jvmkill)


Comments
https://github.com/openjdk/jdk/pull/3586
21-04-2021

The fix is technically simple, but Oracle prefers to keep the xxxOnOutOfMemoryError switches working the way they are now - covering only heap- and Metaspace-OOMs - citing backward compatibility concerns: https://github.com/openjdk/jdk/pull/3586#issuecomment-823963198 ``` I've done some more research and I'm less convinced that this is worth pursuing. You might think it good to add more cases to when these flags get applied but what if existing users of these flags do not want them to be applied to these new cases? You might argue that being unable to start a native thread is something that should trigger a heapdump, or abort the VM, but somebody else may not want that. And even if we agree that most people might want this case, what about the other cases? I certainly don't think that any throwing of OutOfMemoryError should trigger these flags as many of them do not actually reflect being out-of-memory: the OOME is just a proxy for out-of-some-resource. ``` We may add a new set of similar switches handling resource exhaustion scenarios in some future release.
21-04-2021

Oh of course, this was a misunderstanding. I meant I do not aim for completeness wrt all possible OOM sources. But the aim of this hijacked issue is to fix *all* xxxOnOutOfMemoryError switches (HeapDump.. Crash.. Exit.. and the one without which just calls a user command) for thread creation failures.
20-04-2021

I'm not aiming for completeness here. But we have had cases where our support desperately needed this switch to work. E.g. running a JVM inside a container with enough memory but too tight limits for kernel tasks. In these cases users want a very quick shutdown and expect this switch to work (and its difficult to explain why it doesn't)
20-04-2021

This kind of issue has been raised a number of times it seems. My take on this was that these flags were only intended for actual Java heap exhaustion, not for every place the VM chose to throw OOME due to other resource exhaustion.
20-04-2021

You need some degree of completeness though - if the crash option works then all the other variants should work too. Does AbortVMOnException not suffice for those support cases?
20-04-2021

In the case of running out of native threads, we might instead use a blocked thread in a known state, such as the primordial thread.
02-06-2020

I think jdk8u has solved this problem. I got the expected result on both linux and macosx. $java -showversion -Xmx2048k -Xms2048k -XX:+CrashOnOutOfMemoryError Test openjdk version "1.8.0_222" OpenJDK Runtime Environment Corretto-8.222.10.1 (build 1.8.0_222-b10) OpenJDK 64-Bit Server VM Corretto-8.222.10.1 (build 25.222-b10, mixed mode) Aborting due to java.lang.OutOfMemoryError: Java heap space # # A fatal error has been detected by the Java Runtime Environment: # # Internal Error (debug.cpp:308), pid=3904, tid=0x00007fb7120c6700 # fatal error: OutOfMemory encountered: Java heap space # # JRE version: OpenJDK Runtime Environment (8.0_222-b10) (build 1.8.0_222-b10) # Java VM: OpenJDK 64-Bit Server VM (25.222-b10 mixed mode linux-amd64 compressed oops) # Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again # # An error report file with more information is saved as: # /local/home/xxinliu/hs_err_pid3904.log # # If you would like to submit a bug report, please visit: # http://bugreport.java.com/bugreport/crash.jsp # zsh: abort java -showversion -Xmx2048k -Xms2048k -XX:+CrashOnOutOfMemoryError Test
31-10-2019

After exploring the code base I have found there are many types of OutOfMemoryError. 1. java.lang.OutOfMemoryError: Java heap space This error will be triggered when the application attempts to add more data into the heap space area, but there is not enough room for it. Note that there might be plenty of physical memory available, but the java.lang.OutOfMemoryError: Java heap space error is thrown whenever the JVM reaches the heap size limit. 2. java.lang.OutOfMemoryError: GC overhead limit exceeded This error means that the GC tried to free memory but was pretty much unable to get anything done. By default it happens when the JVM spends more than 98% of the total time in GC and when after GC less than 2% of the heap is recovered. 3. java.lang.OutOfMemoryError: Metaspace/Compressed class space Main cause for the this error is either too many classes or too big classes being loaded to the Metaspace. 4. java.lang.OutOfMemoryError: Unable to create new native thread Whenever the underlying OS cannot allocate a new native thread, this OutOfMemoryError will be thrown. The exact limit for native threads is very platform-dependent 5. java.lang.OutOfMemoryError: Out of swap space? This error is thrown by JVM when an allocation request for bytes from the native heap fails and the native heap is close to exhaustion. It is often caused by operating system level issues, such as: a. The operating system is configured with insufficient swap space. b. Another process on the system is consuming all memory resources. 6. java.lang.OutOfMemoryError: Requested array size exceeds VM limit This means that the application that crashes with the error is trying to allocate an array larger than the Java Virtual Machine can support
01-08-2016

I believe we should simply add the check for "OnOutOfMemory" flags to when we fail to allocate native threads. If you do see this failure and you add any of these flags, it probably is because you want to debug that issue. According to David, this is not fixed in 9, but the test itself is somewhat non-deterministic as it depends on how we run out of memory first.
02-05-2016

I would not expect this to work fine in 9-b115 as we do not invoke the code that checks CrashOnOutOfMemoryError when we fail to allocate a native thread - we simply do: THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), os::native_thread_creation_failed_msg());
26-04-2016

This works fine with windows and doesn't work well with linux, Even after throwing exception, program is still running, required to press contr+C to come out. -sh-4.1$ /opt/java/jdk1.8.0_92/bin/java -Xmx2048k -Xms2048k -XX:+CrashOnOutOfMemoryError Test Exception in thread "Thread-0" java.lang.OutOfMemoryError: unable to create new native thread at java.lang.Thread.start0(Native Method) at java.lang.Thread.start(Thread.java:714) at Test.lambda$main$1(Test.java:13) at java.lang.Thread.run(Thread.java:745) ^C-sh-4.1$
25-04-2016