What is the best way to handle out of memory conditions in Java?
The only real option is (unfortunately) to terminate the JVM as soon as possible.
Since you probably cant change all your code to catch the error and respond. If you don't trust the OnOutOfMemoryError
(I wonder why it should not use vfork which is used by Java 8, and it works on Windows), you can at least trigger an heapdump and monitor externally for those files:
java .... -XX:+HeapDumpOnOutOfMemoryError "-XX:OnOutOfMemoryError=kill %p"
After experimenting with this for quite some time, this is the solution that worked for us:
- In the spawned JVM, catch an
OutOfMemoryError
and exit immediately, signalling the out of memory condition with an exit code to the controller JVM. - In the spawned JVM, periodically check the amount of consumed memory of the current
Runtime
. When the amount of memory used is close to critical, create a flag file that signals the out of memory condition to the controller JVM. If we recover from this condition and exit normally, delete that file before we exit. - After the controlling JVM joins the forked JVM, it checks the exit code generated in step (1) and the flag file generated in step (2). In addition to that, it checks whether the file
hs_err_pidXXX.log
exists and contains the line "Out of Memory Error". (This file is generated by java in case it crashes.)
Only after implementing all of those checks were we able to handle all cases where the forked JVM ran out of memory. We believe that since then, we have not missed a case where this happened.
The java flag -XX:OnOutOfMemoryError
was not used because of the fork problem, and -XX:+HeapDumpOnOutOfMemoryError
was not used because a heap dump is more than we need.
The solution is certainly not the most elegant piece of code ever written, but did the job for us.