JVM をクラッシュするにはどうすればよいでしょうか?

StackOverflow https://stackoverflow.com/questions/65200

  •  09-06-2019
  •  | 
  •  

質問

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

誰か何かアイデアはありますか?

役に立ちましたか?

解決

単一の「答え」に最も近いものは、 System.exit() これにより、適切なクリーンアップが行われずに JVM が即座に終了します。しかし、それとは別に、ネイティブ コードとリソースの枯渇が最も可能性の高い答えです。あるいは、Sun のバグ トラッカーで、お使いのバージョンの JVM のバグを探すこともできます。その中には、繰り返し発生するクラッシュ シナリオが考えられるものもあります。以前は、32 ビット バージョンで 4 GB のメモリ制限に近づくと、準定期的にクラッシュが発生していました (現在は通常 64 ビットを使用しています)。

他のヒント

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

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

最後の方法については、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:。クラッシュ

私もこの質問に遭遇したのでここに来ました 情熱的なプログラマー, 、チャド・ファウラー著。コピーを入手できない人のために、この質問は、「本当に優れた Java プログラマー」を必要とする職に面接する候補者向けの一種のフィルター/テストとして構成されています。

具体的に彼は次のように尋ねます。

Java 仮想マシンをクラッシュさせるプログラムを Pure Java でどのように作成しますか?

私は 15 年以上 Java でプログラミングしてきましたが、この質問は不可解で不公平であると感じました。他の人が指摘しているように、Java はマネージ言語として特別に設計されています。 衝突しないように. 。もちろん、JVM のバグは常に存在しますが、次のとおりです。

  1. 15 年以上実稼働レベルの JRE を使用してきた後では、これはまれです。
  2. このようなバグは次のリリースでパッチされる可能性があります。では、プログラマとして、現在の JRE の目玉セットの詳細に遭遇してその詳細を思い出す可能性はどのくらいありますか?

他の人が述べたように、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 または同様の例外ですが、これもまた 実際にはクラッシュではありません.

それで、何が残っているのでしょうか?著者が適切な解決策として実際に何を考えていたのかをぜひ聞きたいです。

アップデート:チャド・ファウラー ここで返信しました.

追伸:それ以外は素晴らしい本です。Ruby を学習する際の精神的なサポートとしてこれを手に取りました。

このコードは JVM をひどい方法でクラッシュさせます

import sun.dc.pr.PathDasher; 

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

前回試したときは次のようになります。

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

完璧な 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 を作成する必要がありました)。:)

Java仮想マシン Jon Meyer による、JVM のコア ダンプを引き起こした一連のバイトコード命令の例があります。この本の私のコピーが見つかりません。持っている人がいたら、調べて答えを投稿してください。

winxpsp2 wmp10 jre6.0_7 上

Desktop.open(uriToAviOrMpgFile)

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

YMMV

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

可能な限り最短の方法:)

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

クラッシュではありませんが、使用するという受け入れられた答えよりもクラッシュに近いです System.exit

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

Runtime.getRuntime().halt( status )

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

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

ここでは、JVM がコア ダンプを行う原因についての詳細な説明を示します (つまり、クラッシュ):http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_17534

クラッシュを、未処理の状況によるプロセスの中止として定義した場合 (つまり、Java 例外またはエラーがない場合)、これを Java 内から実行することはできません (sun.misc.Unsafe クラスを使用する権限がない限り)。これがマネージド コードの要点です。

ネイティブ コードでの一般的なクラッシュは、ポインタが間違ったメモリ領域 (ヌル アドレスまたはアライメントがずれている) を逆参照することによって発生します。別の原因としては、不正な機械命令 (オペコード) や、ライブラリまたはカーネル呼び出しからの未処理の信号が考えられます。JVM またはシステム ライブラリにバグがある場合、両方ともトリガーされる可能性があります。

たとえば、JIT (生成) コード、ネイティブ メソッド、またはシステム コール (グラフィック ドライバー) には、実際のクラッシュにつながる問題が発生する可能性があります (ZIP 関数を使用してメモリが不足したときにクラッシュが発生するのはよくあることです)。このような場合、JVM のクラッシュ ハンドラーが起動し、状態をダンプします。OS コア ファイルを生成することもできます (Dr.Windows ではワトソン、*nix ではコア ダンプ)。

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

メモリが不足しているふりをしたい場合は、次のようにすることができます

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

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

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

無限に多くのスレッドを生成するスレッド プロセスを作成すると (さらに多くのスレッドが生成され、それが...)、最終的には 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分後、RAMを見てください)

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:
# 

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

今やってるけどやり方がよく分からない…:-) JVM (および私のアプリ) は時々完全に消えてしまいます。エラーはスローされず、何も記録されません。警告なしで、動作状態からまったく動作しなくなる状態が即座に発生します。

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

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

Linux および Java 9 以降でのみ動作します。

なぜか腑に落ちないのですが、 ProcessHandle.current().destroyForcibly(); JVMを強制終了せずにスローします java.lang.IllegalStateException メッセージ付き 現在のプロセスの破棄は許可されていません.

その無限 for ループを同じ関数の再帰呼び出しに変更すると、スタック オーバーフロー例外が発生します。

public static void main(String[] args) {
    causeStackOverflow();
}

public void causeStackOverflow() {
    causeStackOverflow();
}

「クラッシュ」が jvm/プログラムの正常終了を中断するものである場合、未処理の例外によってこれが発生する可能性があります。

public static void main(String args[]){
   int i = 1/0;
   System.out.print(i); // This part will not be executed due to above  unhandled exception
  }

つまり、クラッシュの種類によって異なります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top