nekop's blog

OpenShift / JBoss / WildFly / Infinispanの中の人 http://twitter.com/nekop

OutOfMemoryErrorが発生したときにきちんとJavaプロセスを殺す

OutOfMemoryErrorが発生してもスレッドを異空間に葬るだけでJava VMはそのまま動き続ける場合があるけど、当然ながら状態に一貫性のない状態で動いている可能性があるわけで基本的にはとっとと死んで欲しいわけである。一般的に言うところの「不定」状態。OOMEはErrorであってふつうの例外ではなく、致命的なJava VMエラーを示すものである。OOME発生後にプロセス再起動しないでそのままどうこうしようというのは絶対に避けた方が良い。

例えばJDBCのコネクションオープンしてDBからデータを読み込んでるときにOOMEが起きた場合、JDBCコネクションは大抵オープンしっぱなしで回収はされなかったりする。OOMEではfinallyブロックが呼ばれる保証はない。JDBCコネクションリークくらいならまだ良い方だが、これは全てに当てはまる。A-B-Cといったセットになっている処理は例外など起きないと思っていたAの後の時点で強制終了になっていてオブジェクトの状態が中途半端な状態になっている、ということが発生する。このまま動かし続けようものなら業務処理などで致命的なデータ不整合などが発生する場合もあるので、本番環境ではOOME発生時は速やかに殺したいところ。OOMEが発生した後もなんとなくきちんと動いてるように見えるが、実際にはとてつもなくひどいことが起こっている、というのは最悪のシナリオだ。ありとあらゆる前提がひっくり返っている可能性があるので、本当にどうしようもない。

というわけで以下のオプションを設定しておくとすぐ殺せる。Sun Java 6/OpenJDKで使える。他のJVMは知らない。

-XX:OnOutOfMemoryError="kill -9 %p"

実際にOOMEを起こすとこのような出力が標準出力に出る。

#
# java.lang.OutOfMemoryError: Java heap space
# -XX:OnOutOfMemoryError="kill -9 %p"
#   Executing /bin/sh -c "kill -9 12345"...