著者がインタビュイーに「JVMをどのようにクラッシュさせるのですか?」と尋ねるプログラミングスキルに関する本を読んでいました。最終的にすべてのメモリを使い果たす無限のforループを作成することで、そうすることができると思いました。
誰かが何か考えを持っていますか?
OutOfMemoryError または StackOverflowError をスローすることをクラッシュとは呼びません。これらは通常の例外です。VM を実際にクラッシュさせるには、次の 3 つの方法があります。
最後の方法として、Sun Hotspot VM を静かにクラッシュさせる簡単な例を示します。
public class Crash {
public static void main(String[] args) {
Object[] o = null;
while (true) {
o = new Object[] {o};
}
}
}
これにより、GC でスタック オーバーフローが発生するため、StackOverflowError は発生しませんが、hs_err* ファイルを含む実際のクラッシュが発生します。
JNI。実際、JNI では、クラッシュがデフォルトの動作モードです。クラッシュしないようにするには、さらに努力する必要があります。
これを使って:
import sun.misc.Unsafe;
public class Crash {
private static final Unsafe unsafe = Unsafe.getUnsafe();
public static void crash() {
unsafe.putAddress(0, 0);
}
public static void main(String[] args) {
crash();
}
}
このクラスは信頼できるコードを使用しているため、ブートクラスパス上にある必要があります。次のように実行します。
java -Xbootclasspath/p:。クラッシュ
編集:pushyの提案による簡略化されたバージョン:
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
unsafe.putAddress(0, 0);
私がここに来たのは、Chad Fowler 著の The Passionate Programmerでこの質問にも出くわしたからです。コピーにアクセスできない人のために、この質問は、「本当に優れた Java プログラマー」を必要とするポジションの面接を受ける候補者のための一種のフィルター/テストとして構成されています。
具体的には、彼は尋ねます:
Java 仮想マシンをクラッシュさせるプログラムをピュア Java でどのように作成しますか?
私は 15 年以上にわたって Java でプログラミングしてきましたが、この質問は不可解で不公平であることがわかりました。他の人が指摘しているように、マネージド言語である Java はクラッシュしないように特別に設計されています。もちろん、JVM のバグは常に存在しますが、
他の人が言及したように、JNI を介した一部のネイティブ コードは、JRE をクラッシュさせる確実な方法です。しかし、著者は純粋な Javaで具体的に言及したので、それはありません。
もう 1 つのオプションは、JRE の偽のバイト コードをフィードすることです。ガベージ バイナリ データを .class ファイルにダンプし、JRE に実行を依頼するのは簡単です。
$ echo 'crap crap crap' > crap.class
$ java crap
Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 1668440432 in class file crap
それは重要ですか?つまり、JRE 自体はクラッシュしていません。偽のコードを適切に検出し、それを報告して終了しました。
これにより、再帰によるスタックの吹き飛ばし、オブジェクトの割り当てによるヒープメモリの不足、または単にRuntimeException
. しかし、これは JRE がStackOverflowError
または同様の例外で終了するだけであり、これも実際には crash ではありません。
それで、何が残っていますか?適切な解決策として著者が本当に考えていたことを聞きたいです。
更新: Chad Fowlerがここに回答しました。
PS: それ以外は素晴らしい本です。Rubyを学びながら道徳的なサポートのためにそれを手に入れました.
このコードは、厄介な方法で JVM をクラッシュさせます
import sun.dc.pr.PathDasher;
public class Crash
{
public static void main(String[] args)
{
PathDasher dasher = new PathDasher(null) ;
}
}
完璧な JVM 実装は決してクラッシュしません。
JNI は別として、JVM をクラッシュさせるには、VM 自体のバグを見つける必要があります。無限ループは単に CPU を消費します。メモリを無限に割り当てると、適切に構築された JVM で OutOfMemoryError が発生するだけです。これはおそらく他のスレッドに問題を引き起こす可能性がありますが、それでも優れた JVM はクラッシュしないはずです。
VM のソース コードにバグが見つかった場合、たとえば VM の実装のメモリ使用量でセグメンテーション エラーが発生した場合は、実際に VM をクラッシュさせることができます。
JVM をクラッシュさせたい場合 - Sun JDK 1.6_23 以下で以下を使用します。
Double.parseDouble("2.2250738585072012e-308");
これは Sun JDK のバグによるもので、OpenJDK にも見られます。これは、Oracle JDK 1.6_24 以降で修正されています。
クラッシュの意味によって異なります。
無限再帰を実行してスタックスペースを使い果たすことができますが、それは「正常に」クラッシュします。例外が発生しますが、JVM自体がすべてを処理します。
JNIを使用してネイティブコードを呼び出すこともできます。あなたがそれを正しくやらないなら、あなたはそれを激しくクラッシュさせることができます。これらのクラッシュのデバッグは「楽しい」です(私を信じてください。署名されたJavaアプレットから呼び出す大きなC ++ DLLを作成する必要がありました)。:)
単一の「答え」に最も近いのはSystem.exit()
、適切なクリーンアップなしでJVMをすぐに終了することです。しかし、それとは別に、ネイティブコードとリソースの枯渇が最も可能性の高い答えです。または、Sunのバグトラッカーを調べて、ご使用のバージョンのJVMのバグを探すこともできます。その中には、繰り返し発生するクラッシュシナリオを可能にするものもあります。以前は、32ビットバージョンで4 Gbのメモリ制限に近づくと、半定期的にクラッシュしていました(現在は通常64ビットを使用しています)。
Jon Meyer による本Java Virtual Machineには、JVM のコア ダンプを引き起こした一連のバイトコード命令の例があります。この本のコピーが見つかりません。誰かが持っている場合は、それを調べて回答を投稿してください。
winxpsp2 w /wmp10jre6.0_7で
Desktop.open(uriToAviOrMpgFile)
これにより、生成されたスレッドがキャッチされていないThrowableをスローし、ホットスポットをクラッシュさせます
YMMV
最短の方法:)
public class Crash
{
public static void main(String[] args)
{
main(args);
}
}
ハードウェアが壊れると、あらゆるプログラムがクラッシュする可能性があります。まったく同じセットアップの他のマシンでは正常に実行されているのに、特定のマシンでアプリが再現可能にクラッシュしたことがあります。そのマシンの RAM に障害があることが判明しました。
クラッシュではありませんが、使用の受け入れられた答えよりもクラッシュに近いですSystem.exit
を呼び出して JVM を停止できます。
Runtime.getRuntime().halt( status )
ドキュメントによると:-
「終了時のファイナライズが有効になっている場合、このメソッドはシャットダウン フックを開始せず、呼び出されていないファイナライザーを実行しません」。
未処理の状況(つまり、Java例外またはエラーがない)が原因でクラッシュをプロセスアボートとして定義した場合、Java内からこれを実行することはできません(sun.misc.Unsafeクラスを使用する権限がない場合)。これがマネージコードの要点です。
ネイティブコードでの一般的なクラッシュは、間違ったメモリ領域へのポインタの参照を解除することで発生します(nullアドレスまたはミスアラインメント)。別のソースは、不正なマシン命令(オペコード)またはライブラリまたはカーネル呼び出しからの未処理のシグナルである可能性があります。JVMまたはシステムライブラリにバグがある場合は、両方をトリガーできます。
たとえば、JITされた(生成された)コード、ネイティブメソッド、またはシステムコール(グラフィックスドライバー)では、実際のクラッシュにつながる問題が発生する可能性があります(ZIP関数を使用してメモリが不足すると、クラッシュすることがよくありました)。このような場合、JVMのクラッシュハンドラーが起動して状態をダンプします。また、OSコアファイル(WindowsではDr. Watson、* nixではコアダンプ)を生成することもできます。
Linux / Unixでは、実行中のプロセスにシグナルを送信することで、JVMを簡単にクラッシュさせることができます。SIGSEGV
注:ホットスポットはこの信号をキャッチし、ほとんどの場所でNullPointerExceptionとして再スローするため、これには使用しないでください。したがってSIGBUS
、たとえばを送信することをお勧めします。
メモリが不足しているふりをしたい場合は、次のことができます
public static void main(String[] args) {
throw new OutOfmemoryError();
}
ネイティブ メソッド (組み込みメソッド) を呼び出して JVM にエラー ファイルをダンプさせる方法をいくつか知っていますが、その方法を知らない方がよいでしょう。;)
JVM のコア ダンプ (クラッシュ) の原因について詳しく説明します: http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_17534
最短?Robot クラスを使用して CTRL+BREAK をトリガーします。コンソールを閉じずにプログラムを閉じようとしていたときにこれを見つけました (「終了」機能がありませんでした)。
その無限ループを同じ関数への再帰呼び出しに変更すると、スタックオーバーフロー例外が発生します。
public static void main(String[] args) {
causeStackOverflow();
}
public void causeStackOverflow() {
causeStackOverflow();
}
私は今それをやっていますが、方法が完全にはわかりません... :-) JVM(および私のアプリ)が完全に消えることがあります。エラーはスローされず、何も記録されません。警告なしで、すぐに動作からまったく実行されなくなります。