“Failed to write core dump”

原文はこちら。
The original article was written by Joakim Nordström (Principal Member of Technical Staff, JVM Sustaining Engineering group at Oracle).
https://inside.java/2021/04/30/failed-writing-core-dump/

JVMがクラッシュした際に生成されるhs_errというHotSpotエラーファイルの調査をしてきました。よくあるエラーはコアダンプの書き込みに失敗する、というものです。

“Failed to write coredump.”

コアダンプ書き込みの失敗はしかしながらJVMをクラッシュさせるエラーではなく、コアダンプが書き込まれなかったことをJVMが通知しているのに過ぎません。

TL;DR コアダンプ書き込み失敗を解消したいだけならば、利用するための引数に直接飛べばよいのです。

Nota bene(注意) これはクラッシュを解決するのではありません。システムを埋め尽くす大きなファイル、つまりコアダンプが発生するだけです。

コアダンプ、もしくはWindowsにおけるMinidumpは、クラッシュしたプロセスのスナップショットです。例えて言えば、JVMがドライブ中の車だとして、突然、他の車やレンガの壁、態度の悪いドライバーなど、何かに衝突した場合を想像してみてください。保険会社が何が起こったのかを見て調べるために、JVMはクラッシュした場所の写真を撮ることができるのです。

OSによって、コアダンプの作成方法は異なります。Windowsでは、dbghelp.dllというDLLにMiniDumpWriteDump関数があり、JVMがこれを起動してコアダンプを生成します。POSIX系OS(Unix、Linux、macOS)では、abort()関数を呼び出すことで、OSがコアダンプを生成します。

コア・ダンプの書き込みを有効にするJVM引数の-XX:+CreateCoredumpOnCrashは、JDK9以上ではデフォルトで有効になっています。JDK 8の場合、この引数は-XX:+CreateMinidumpOnCrashで、これはWindowsでのみ意味を持ちます。他のOSではこの引数は無視されます。

Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
(コアダンプの書き出しに失敗しました。MinidumpはWindowsのクライアント版ではデフォルトで有効化されていません)

“Minidumps are not enabled by default on client versions of Windows”というメッセージのクライアントとは、Windows Serverに対するWindows Clientでの動作を意味しており、昔のHotSpotのCklient/Server VMの区別と混同しないでください。

Java Virtual Machine Technology
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/index.html
Java仮想マシン・テクノロジ
https://docs.oracle.com/javase/jp/8/docs/technotes/guides/vm/index.html

Windowsクライアントでは、minidumpを書き込むようにJVMに指示しなければなりません。これはWindows自体とは関係ないので、Windowsの設定を変更する必要はありません(Windowsがクラッシュしたときの設定を有効にするという提案もありますが、ここでは適用されません)。minidumpファイル(かなり大きくなる可能性があります)がWindowsクライアントユーザーのディスクスペースを埋めてしまわないように、Windowsクライアント版で実行しているかどうかのチェックをJVMで明示的に行っています。しかし、Windows Serverでは、minidumpはデフォルトで有効になっています。

How to enable core dumps/minidumps

JDK 9 and above

任意のOSでJDK 9以後でコアダンプを有効化するには、Javaランチャーに -XX:+CreateCoredumpOnCrash という引数を追加するだけです。

java -jar crasher.jar -XX:+CreateCoredumpOnCrash

コアダンプを無効にしたいなら、+を-にした引数に置き換えます。つまり、-XX:-CreateCoredumpOnCrashを指定します。

JDK 8 on Windows

JDK 8が動作しているWindowsクライアント版では、 -XX:+CreateMinidumpOnCrash を追加し、JVMクラッシュ時にminidumpを作成するようにします。

java -jar crasher.jar -XX:+CreateMinidumpOnCrash

Windows Serverでコアダンプを無効化したい場合は、+を-にします。つまり、-XX:-CreateMinidumpOnCrashを引数に指定します。

POSIX系OSでJDK 8を使っている場合、コアダンプを無効化するJVMの引数はありません。その代わりに、OSレベルでコアダンプを無効化しなければなりません。

Unix, Linux, and macOS core dumps

POSIX系OSでは、コアダンプをOSレベルで無効化できます。このような場合、JVMは「Core dumps have been disabled(コアダンプが無効化されています)」と報告します。

Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
(コアダンプの書き込みに失敗しました。コア・ダンプは無効になっています。コア・ダンプを有効にするには、Javaを再起動する前に、”ulimit -c unlimited “を実行してください。)

コアダンプのファイルサイズを制御するには、ulimitコマンドと-c引数を使用します。0に設定するとコアダンプが無効になり、unlimitedに設定すると有効になります。ulimit -c unlimitedを実行すると、すべてのユーザーとすべてのプログラムでコアダンプが有効になります。ですから、まずOSレベルでコアダンプを有効にしてから、Javaプログラムを実行してください。そして、JDK9以上の場合は、-XX:+CreateCoredumpOnCrashを追加する必要があることを覚えておいてください。

ulimit -c unlimited
java -jar crasher.jar -XX:+CreateCoredumpOnCrash

Summary of arguments

表にまとめると、JDK9以降では、コアダンプ/ミニダンプの扱いがより一貫していることがわかります。この一貫性は、JDK-8074354 “Make CreateMinidumpOnCrash a new name and available on all platforms” でJDK 9に追加されました。

Make CreateMinidumpOnCrash a new name and available on all platforms
https://bugs.openjdk.java.net/browse/JDK-8074354

下記の2表は、コアダンプの書き込みを有効にするための引数と、無効にするためのOSの要件をそれぞれまとめたものです。プラスとマイナスの記号に注意してください。

Enabling core dumps

この表では、デフォルトの動作をオーバーライドするために必要な設定を太字で示しています(つまり、Windowsクライアントでのみ、コアダンプを明示的に有効にする必要があります)。

OSJDK 8での引数JDK 9以後での引数OSレベルの制御要否
Windows client-XX:+CreateMinidumpOnCrash-XX:+CreateCoredumpOnCrashN/A
Windows server-XX:+CreateMinidumpOnCrash-XX:+CreateCoredumpOnCrashN/A
POSIXN/A (常に有効)-XX:+CreateCoredumpOnCrashulimit -c unlimited

Disabling core dumps

2番目の表はコアダンプを無効化する方法を示したものです。太字はデフォルトの動作をオーバーライドするために必要な設定です。

OSJDK 8JDK 9-OSレベルの制御要否
Windows client-XX:-CreateMinidumpOnCrash-XX:-CreateCoredumpOnCrashN/A
Windows server-XX:-CreateMinidumpOnCrash-XX:-CreateCoredumpOnCrashN/A
POSIXN/A (常に有効)-XX:-CreateCoredumpOnCrashulimit -c 0

What can be found in a core dump that can’t be found in the hs_err file? (hs_errファイルで見つけられずコアダンプで見つけられるものは?)

コアダンプはhs_errテキストファイルの優れた追加機能です。コアダンプを調べるにはネイティブデバッガーが必要です。

生成されたhs_errファイルを見るだけで、極めて多くのことがわかります。

# Problematic frame:
# C  [dump.dll+0x1006]
#
# Core dump will be written. Default location: D:\dumpster\hs_err_pid29804.mdmp
[...]

Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [dump.dll+0x1006]

Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  jaokim.dumpster.Divider.native_div_call(I)I+0
j  jaokim.dumpster.Divider.do_div(I)I+2
j  jaokim.dumpster.Dumpster.do_loops(I)V+16
j  jaokim.dumpster.Dumpster.doTestcase(Ljava/lang/Integer;)V+5
j  jaokim.dumpster.Dumpster.main([Ljava/lang/String;)V+58
v  ~StubRoutines::call_stub

siginfo: EXCEPTION_INT_DIVIDE_BY_ZERO (0xc0000094)

クラッシュが発生した問題のフレームはネイティブコードのdump.dll内であり、コアダンプが書き出されたことがわかります。

A crash happened outside the Java Virtual Machine
https://inside.java/2020/12/03/crash-outside-the-jvm/

このネイティブメソッドは、jaokim.dumpster.Divider.native_div_callというJavaメソッドが呼び出していました。また、ある種のゼロ除算の例外(EXCEPTION_INT_DIVIDE_BY_ZERO)と思われる現象も確認できます。しかし、dump.dllのネイティブコードの詳細を知りたい場合、hs_errファイルではこれ以上の情報は得られません。

こうした失われた詳細情報を取得するには、ネイティブデバッガー(Windowsの場合はWinDbg)と生成されたコアダンプを使う必要があります。以下はクラッシュしている行を直接示すWinDbgのスクリーンショットです。

Screenshot of WinDbg showing the faulting source line.

正確なソースコードの行を知るためには、ネイティブデバッガーがデバッグシンボルを持っている必要があります。Windowsの場合、これらはdump.dllをコンパイルした際に生成される.pdbファイルにあります。(.pdbファイルをコアダンプと同じディレクトリに置くとWinDbgが.pdbファイルを見つけることができます)。POSIX系OSでは、共有オブジェクト(dump.so)をデバッグシンボルをONにしてコンパイルする必要があります。

Summary

JVMがクラッシュすると、クラッシュしたプロセスの詳細を含むコアダンプを書き出すことができます。コアダンプの書き出しが無効化されている場合、JVMはコアダンプ書き込みに失敗したことを知らせてくれます。しかし、これはJVMがクラッシュした実際の原因・理由とは無関係です。クラッシュの理由は、ほとんどの場合、hs_errファイルに記載されており、より複雑な詳細はコアダンプに記載されています。

通常、ほとんどの開発車はコアダンプを必要とはしませんが、その代わりにhs_errファイルに注目してどのコンポーネントが原因でクラッシュしたのかを最初に見つけるべきです。

このエントリで紹介したサンプルコードはGitHubにあります。

jaokim/inside-java-dumpster
https://github.com/jaokim/inside-java-dumpster

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中