web-dev-qa-db-ja.com

JVMをどのようにクラッシュさせますか?

著者はインタビューの相手に「JVMをクラッシュさせるにはどうすればいいですか?」と尋ねるプログラミングスキルに関する本を読んでいました。最終的にすべてのメモリを使い果たす無限のforループを書くことでそうできると思った。

誰もが考えていますか?

141

単一の「答え」に最も近いものはSystem.exit()で、これは適切なクリーンアップなしですぐにJVMを終了します。しかし、それとは別に、ネイティブコードとリソースの枯渇が最も可能性の高い答えです。または、Sunのバグトラッカーで、お使いのバージョンのJVMのバグを確認することもできます。バグの一部は、再現可能なクラッシュシナリオを可能にします。以前は、32ビットバージョンで4 Gbのメモリ制限に近づくと、半定期的なクラッシュが発生していました(現在は一般に64ビットを使用しています)。

6
Leigh Caldwell

OutOfMemoryErrorまたはStackOverflowErrorのスローをクラッシュとは呼びません。これらは通常の例外です。 VMを本当にクラッシュさせるには、3つの方法があります。

  1. JNIを使​​用して、ネイティブコードでクラッシュします。
  2. セキュリティマネージャがインストールされていない場合、リフレクションを使用してVMをクラッシュできます。これはVM固有ですが、通常はVMはネイティブリソースへのポインタをプライベートフィールドに格納しますJava.lang.Thread)の長いフィールド。リフレクションで変更するだけで、VMは遅かれ早かれクラッシュします。
  3. すべてのVMにはバグがあるため、トリガーする必要があります。

最後の方法については、Sun Hotspotをクラッシュさせる短い例がありますVM quiet:

public class Crash {
    public static void main(String[] args) {
        Object[] o = null;

        while (true) {
            o = new Object[] {o};
        }
    }
}

これにより、GCでスタックオーバーフローが発生するため、StackOverflowErrorは発生しませんが、hs_err *ファイルを含む実際のクラッシュが発生します。

172
ralfs

[〜#〜] jni [〜#〜] 。実際、JNIでは、クラッシュがデフォルトの操作モードです。クラッシュしないようにするには、余分な努力が必要です。

123
Dan Dyer

これを使って:

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:。クラッシュ

56
Dave Griffiths

チャド・ファウラーによる The Passionate Programmer でこの質問に出くわしたので、私はここに来ました。コピーにアクセスできない人のために、質問は「本当に良いJavaプログラマー」を必要とするポジションの面接候補者のための一種のフィルター/テストとして組み立てられています。

具体的には、彼は尋ねます:

Java仮想マシンをクラッシュさせるプログラムを、純粋なJavaでどのように記述しますか?

私はJavaで15年以上プログラミングしましたが、この質問は不可解で不公平であることがわかりました。他の人が指摘したように、マネージ言語としてのJavaは特に設計されていますクラッシュしない。もちろん、常にJVMバグがありますが、

  1. 15年以上の実稼働レベルのJREの後、それはまれです。
  2. そのようなバグは次のリリースで修正される可能性が高いので、現在のJREショーストッパーのセットの詳細にぶつかり、それを思い出すプログラマーとしてどれくらいありそうですか?

他の人が言及したように、JNIを介した一部のネイティブコードは、JREをクラッシュさせる確実な方法です。しかし、著者は具体的にin pure Javaに言及したので、これは出ていません。

別のオプションは、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または同様の例外で終了します。これも、は実際にはクラッシュではありませんです。

それで、何が残っていますか?著者が適切な解決策として本当に考えていたことを聞きたいです。

更新:チャド・ファウラー ここで回答 .

PS:それは他の点では素晴らしい本です。 Rubyを学んでいる間、私はそれを道徳的サポートのために選びました。

32
George Armhold

このコードはJVMを厄介な方法でクラッシュさせます

import Sun.dc.pr.PathDasher; 

public class Crash
{
     public static void main(String[] args)
     {    
        PathDasher dasher = new PathDasher(null) ;
     }
}
20
Rob Mayhew

私がこれを試した最後の時間はそれをするでしょう:

public class Recur {
    public static void main(String[] argv) {
        try {
            recur();
        }
        catch (Error e) {
            System.out.println(e.toString());
        }
        System.out.println("Ended normally");
    }
    static void recur() {
        Object[] o = null;
        try {
            while(true) {
                Object[] newO = new Object[1];
                newO[0] = o;
                o = newO;
            }
        }
        finally {
            recur();
        }
    }
}

生成されたログファイルの最初の部分:

#
# An unexpected error has been detected by Java Runtime Environment:
#
#  EXCEPTION_STACK_OVERFLOW (0xc00000fd) at pc=0x000000006dad5c3d, pid=6752, tid=1996
#
# Java VM: Java HotSpot(TM) 64-Bit Server VM (11.2-b01 mixed mode windows-AMD64)
# Problematic frame:
# V  [jvm.dll+0x2e5c3d]
#
# If you would like to submit a bug report, please visit:
#   http://Java.Sun.com/webapps/bugreport/crash.jsp
#

---------------  T H R E A D  ---------------

Current thread (0x00000000014c6000):  VMThread [stack: 0x0000000049810000,0x0000000049910000] [id=1996]

siginfo: ExceptionCode=0xc00000fd, ExceptionInformation=0x0000000000000001 0x0000000049813fe8 

Registers:
EAX=0x000000006dc83090, EBX=0x000000003680f400, ECX=0x0000000005d40ce8, EDX=0x000000003680f400
ESP=0x0000000049813ff0, EBP=0x00000000013f2df0, ESI=0x00000000013f0e40, EDI=0x000000003680f400
EIP=0x000000006dad5c3d, EFLAGS=0x0000000000010206
17
Hot Licks

完璧なJVM実装は決してクラッシュしません。

JVMをクラッシュさせるには、JNIの他に、VM自体にバグを見つける必要があります。無限ループはCPUを消費するだけです。メモリを無限に割り当てると、正しく構築されたJVMで他のスレッドで問題が発生する可能性がありますが、優れたJVMはクラッシュしません。

VMのソースコードにバグがあり、たとえばVMの実装のメモリ使用量にセグメンテーションフォールトが発生している場合は、実際にクラッシュさせることができます。

15
Dave L.

JVMをクラッシュさせる場合-Sun JDK 1.6_23以下で次を使用します。

Double.parseDouble("2.2250738585072012e-308");

これは、Sun JDKの bug によるものです-OpenJDKにもあります。これは、Oracle JDK 1.6_24以降で修正されています。

14

クラッシュの意味に依存します。

無限再帰を実行してスタック領域を使い果たすことができますが、それは「優雅に」クラッシュします。例外が発生しますが、JVM自体がすべてを処理します。

JNIを使​​用してネイティブコードを呼び出すこともできます。正しく実行しないと、クラッシュする可能性があります。これらのクラッシュのデバッグは「楽しい」です(私を信じて、署名済みのDLLアプレット)から呼び出す大きなC++ Javaを書かなければなりませんでした。)。)

10
Herms

Jon Meyerによる本 Java Virtual Machine には、JVMをコアダンプさせる一連のバイトコード命令の例があります。この本のコピーが見つかりません。誰かがそれを持っているならば、それを調べて、答えを投稿してください。

6
Soulfly

壊れたハードウェアは、プログラムをクラッシュさせる可能性があります。特定のマシンで再現性のあるアプリクラッシュが発生したときに、まったく同じ設定で他のマシンで正常に動作していました。マシンのRAMに欠陥があることがわかりました。

5

クラッシュではなく、_System.exit_を使用するという一般に認められた答えよりもクラッシュに近い

を呼び出すことでJVMを停止できます

Runtime.getRuntime().halt( status )

ドキュメントによると:-

「このメソッドはシャットダウンフックを開始せず、終了時のファイナライゼーションが有効になっている場合は、起動されていないファイナライザを実行しません。」.

5
henry

最短の方法:)

public class Crash
{
    public static void main(String[] args)
    {
        main(args);
    }
}
5
RRM

winxpsp2 w/wmp10 jre6.0_7で

Desktop.open(uriToAviOrMpgFile)

これにより、生成されたスレッドがキャッチされていないThrowableをスローし、ホットスポットがクラッシュします

YMMV

5
kitsuneymg

処理されていない状況(つまり、Java例外またはエラー)が原因でプロセスの中断としてクラッシュを定義する場合、これはJava (Sun.misc.Unsafeクラスを使用する権限がない場合)。これがマネージコードのポイントです。

ネイティブコードの典型的なクラッシュは、間違ったメモリ領域(ヌルアドレスまたはミスアラインメント)へのポインタを逆参照することで発生します。別のソースは、違法なマシン命令(オペコード)またはライブラリーまたはカーネル呼び出しからの未処理の信号です。 JVMまたはシステムライブラリにバグがある場合、両方をトリガーできます。

たとえば、JITされた(生成された)コード、ネイティブメソッド、またはシステムコール(グラフィックスドライバー)には、実際のクラッシュにつながる問題があります(Zip関数を使用してメモリ不足になったときにクラッシュするのは非常に一般的でした)。これらの場合、JVMのクラッシュハンドラーが起動し、状態をダンプします。また、OSコアファイル(Windowsではワトソン博士、* nixではコアダンプ)も生成できます。

Linux/Unixでは、実行中のプロセスにシグナルを送信することにより、JVMを簡単にクラッシュさせることができます。注:Hotspotはこの信号をキャッチし、ほとんどの場所でNullPointerExceptionとして再スローするため、SIGSEGVを使用しないでください。したがって、たとえばSIGBUSを送信することをお勧めします。

4
eckes

jVMのコアダンプ(クラッシュなど)の原因について詳しく説明します: http://kb.Adobe.com/selfservice/viewContent.do?externalId=tn_17534

4
COTOHA

あなたができるメモリを使い果たしたふりをしたい場合

public static void main(String[] args) {
    throw new OutOfmemoryError();
}

ネイティブメソッド(組み込みのメソッド)を呼び出してJVMにエラーファイルをダンプさせるいくつかの方法を知っていますが、おそらくこれを行う方法を知らないことが最善です。 ;)

3
Peter Lawrey

JNIはクラッシュの大きな原因です。 JVMTIインターフェイスもC/C++で記述する必要があるため、JVMTIインターフェイスを使用してクラッシュすることもあります。

3
Jared

無限に多くのスレッドを生成するスレッドプロセスを作成すると(より多くのスレッドが生成され、...)、最終的にJVM自体でスタックオーバーフローエラーが発生します。

public class Crash {
    public static void main(String[] args) {

        Runnable[] arr = new Runnable[1];
        arr[0] = () -> {

            while (true) {
                new Thread(arr[0]).start();
            }
        };

        arr[0].run();
    }
}

これは私に出力を与えました(5分後、あなたのラムを見てください)

An unrecoverable stack overflow has occurred.
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_STACK_OVERFLOW (0xc00000fd) at pc=0x0000000070e53ed7, pid=12840, tid=0x0000000000101078
#
# JRE version: Java(TM) SE Runtime Environment (8.0_144-b01) (build 1.8.0_144-b01)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode windows-AMD64 compressed oops)
# Problematic frame:
# 
2
Lightfire228

最短? Robotクラスを使用して、CTRL + BREAKをトリガーします。コンソールを閉じずにプログラムを閉じようとしたときに、これを見つけました(「終了」機能はありませんでした)。

1
user6022288

私は今それをやっていますが、どのように完全にはわからない... :-) JVM(および私のアプリ)は時々完全に消えます。エラーはスローされず、ログにも記録されません。警告なしで、すぐに作業から実行しないようになります。

0
Brian Knoblauch

「クラッシュ」とは、JVMの突然の中止を意味する場合、JVMがhs_err_pid%p.logに書き出すなどの場合、この方法で実行できます。

-Xmx argを小さな値に設定し、メモリ不足でクラッシュを強制するようJVMに指示します。

 -Xmx10m -XX:+CrashOnOutOfMemoryError

明確にするために、上記の2番目の引数がなければ、OutOfMemoryErrorを伴うjvm 終了になりますが、jvmを「クラッシュ」したり、突然中断したりしません。

この手法は、JVM -XX:ErrorFile argをテストするときに役立ちました。この引数は、そのようなhs_err_pidログの書き込み先を制御します。このようなクラッシュを強制する方法を見つけようとしているときに、この投稿をここで見つけました。後で上記が私のニーズに最も簡単に機能することがわかったとき、ここにリストに追加したいと思いました。

最後に、FWIW、-Xms値が既に(上記よりも大きい値に)設定されている場合にこれをテストできる場合、それを削除または変更することもできます。 「初期ヒープサイズが最大ヒープサイズよりも大きい値に設定されている」と報告されるjvmの起動の失敗。 (一部のアプリサーバーなどでJVMをサービスとして実行している場合、それは明らかではありません。繰り返しになりますが、私はそれを共有したかったのです。)

0
charlie arehart

これはカウントされますか?

long pid = ProcessHandle.current().pid();
try { Runtime.getRuntime().exec("kill -9 "+pid); } catch (Exception e) {}

Linuxおよびfrom Java 9。

なんらかの理由でProcessHandle.current().destroyForcibly();がJVMを強制終了せず、Java.lang.IllegalStateExceptionをスローしてメッセージで現在のプロセスの破棄は許可されません

0
mszmurlo