著者はインタビューの相手に「JVMをクラッシュさせるにはどうすればいいですか?」と尋ねるプログラミングスキルに関する本を読んでいました。最終的にすべてのメモリを使い果たす無限のforループを書くことでそうできると思った。
誰もが考えていますか?
単一の「答え」に最も近いものはSystem.exit()
で、これは適切なクリーンアップなしですぐにJVMを終了します。しかし、それとは別に、ネイティブコードとリソースの枯渇が最も可能性の高い答えです。または、Sunのバグトラッカーで、お使いのバージョンのJVMのバグを確認することもできます。バグの一部は、再現可能なクラッシュシナリオを可能にします。以前は、32ビットバージョンで4 Gbのメモリ制限に近づくと、半定期的なクラッシュが発生していました(現在は一般に64ビットを使用しています)。
OutOfMemoryErrorまたはStackOverflowErrorのスローをクラッシュとは呼びません。これらは通常の例外です。 VMを本当にクラッシュさせるには、3つの方法があります。
最後の方法については、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 *ファイルを含む実際のクラッシュが発生します。
[〜#〜] 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:。クラッシュ
チャド・ファウラーによる The Passionate Programmer でこの質問に出くわしたので、私はここに来ました。コピーにアクセスできない人のために、質問は「本当に良いJavaプログラマー」を必要とするポジションの面接候補者のための一種のフィルター/テストとして組み立てられています。
具体的には、彼は尋ねます:
Java仮想マシンをクラッシュさせるプログラムを、純粋なJavaでどのように記述しますか?
私はJavaで15年以上プログラミングしましたが、この質問は不可解で不公平であることがわかりました。他の人が指摘したように、マネージ言語としてのJavaは特に設計されていますクラッシュしない。もちろん、常にJVMバグがありますが、
他の人が言及したように、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を学んでいる間、私はそれを道徳的サポートのために選びました。
このコードは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実装は決してクラッシュしません。
JVMをクラッシュさせるには、JNIの他に、VM自体にバグを見つける必要があります。無限ループはCPUを消費するだけです。メモリを無限に割り当てると、正しく構築されたJVMで他のスレッドで問題が発生する可能性がありますが、優れたJVMはクラッシュしません。
VMのソースコードにバグがあり、たとえばVMの実装のメモリ使用量にセグメンテーションフォールトが発生している場合は、実際にクラッシュさせることができます。
JVMをクラッシュさせる場合-Sun JDK 1.6_23以下で次を使用します。
Double.parseDouble("2.2250738585072012e-308");
これは、Sun JDKの bug によるものです-OpenJDKにもあります。これは、Oracle JDK 1.6_24以降で修正されています。
クラッシュの意味に依存します。
無限再帰を実行してスタック領域を使い果たすことができますが、それは「優雅に」クラッシュします。例外が発生しますが、JVM自体がすべてを処理します。
JNIを使用してネイティブコードを呼び出すこともできます。正しく実行しないと、クラッシュする可能性があります。これらのクラッシュのデバッグは「楽しい」です(私を信じて、署名済みのDLLアプレット)から呼び出す大きなC++ Javaを書かなければなりませんでした。)。)
Jon Meyerによる本 Java Virtual Machine には、JVMをコアダンプさせる一連のバイトコード命令の例があります。この本のコピーが見つかりません。誰かがそれを持っているならば、それを調べて、答えを投稿してください。
壊れたハードウェアは、プログラムをクラッシュさせる可能性があります。特定のマシンで再現性のあるアプリクラッシュが発生したときに、まったく同じ設定で他のマシンで正常に動作していました。マシンのRAMに欠陥があることがわかりました。
クラッシュではなく、_System.exit
_を使用するという一般に認められた答えよりもクラッシュに近い
を呼び出すことでJVMを停止できます
Runtime.getRuntime().halt( status )
ドキュメントによると:-
「このメソッドはシャットダウンフックを開始せず、終了時のファイナライゼーションが有効になっている場合は、起動されていないファイナライザを実行しません。」.
最短の方法:)
public class Crash
{
public static void main(String[] args)
{
main(args);
}
}
winxpsp2 w/wmp10 jre6.0_7で
Desktop.open(uriToAviOrMpgFile)
これにより、生成されたスレッドがキャッチされていないThrowableをスローし、ホットスポットがクラッシュします
YMMV
処理されていない状況(つまり、Java例外またはエラー)が原因でプロセスの中断としてクラッシュを定義する場合、これはJava (Sun.misc.Unsafeクラスを使用する権限がない場合)。これがマネージコードのポイントです。
ネイティブコードの典型的なクラッシュは、間違ったメモリ領域(ヌルアドレスまたはミスアラインメント)へのポインタを逆参照することで発生します。別のソースは、違法なマシン命令(オペコード)またはライブラリーまたはカーネル呼び出しからの未処理の信号です。 JVMまたはシステムライブラリにバグがある場合、両方をトリガーできます。
たとえば、JITされた(生成された)コード、ネイティブメソッド、またはシステムコール(グラフィックスドライバー)には、実際のクラッシュにつながる問題があります(Zip関数を使用してメモリ不足になったときにクラッシュするのは非常に一般的でした)。これらの場合、JVMのクラッシュハンドラーが起動し、状態をダンプします。また、OSコアファイル(Windowsではワトソン博士、* nixではコアダンプ)も生成できます。
Linux/Unixでは、実行中のプロセスにシグナルを送信することにより、JVMを簡単にクラッシュさせることができます。注:Hotspotはこの信号をキャッチし、ほとんどの場所でNullPointerExceptionとして再スローするため、SIGSEGV
を使用しないでください。したがって、たとえばSIGBUS
を送信することをお勧めします。
jVMのコアダンプ(クラッシュなど)の原因について詳しく説明します: http://kb.Adobe.com/selfservice/viewContent.do?externalId=tn_17534
あなたができるメモリを使い果たしたふりをしたい場合
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分後、あなたのラムを見てください)
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(および私のアプリ)は時々完全に消えます。エラーはスローされず、ログにも記録されません。警告なしで、すぐに作業から実行しないようになります。
「クラッシュ」とは、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をサービスとして実行している場合、それは明らかではありません。繰り返しになりますが、私はそれを共有したかったのです。)
これはカウントされますか?
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
をスローしてメッセージで現在のプロセスの破棄は許可されません。