プログラミングスキルについての本を読んでいて、著者がインタビュー対象者に「JVMをクラッシュさせるにはどうすればよいですか」と尋ねました。最終的にすべてのメモリを使い果たす無限のforループを作成することで、そうすることができると思いました。
誰かが何か考えを持っていますか?
プログラミングスキルについての本を読んでいて、著者がインタビュー対象者に「JVMをクラッシュさせるにはどうすればよいですか」と尋ねました。最終的にすべてのメモリを使い果たす無限のforループを作成することで、そうすることができると思いました。
誰かが何か考えを持っていますか?
回答:
単一の「答え」に最も近いのはSystem.exit()
、適切なクリーンアップなしでJVMを即座に終了させることです。しかし、それとは別に、ネイティブコードとリソースの枯渇が最も可能性の高い答えです。または、Sunのバグトラッカーを調べて、ご使用のバージョンのJVMのバグを探すこともできます。その一部は、繰り返し発生するクラッシュシナリオを可能にします。以前は、32ビットバージョンで4 Gbのメモリ制限に近づくと、半定期的なクラッシュが発生していました(現在は通常64ビットを使用しています)。
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 *ファイルを含む実際のクラッシュが発生します。
java.lang.OutOfMemoryError: GC overhead limit exceeded
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:。クラッシュ
Field f = Unsafe.class.getDeclaredField( "theUnsafe" ); f.setAccessible( true ); unsafe = (Unsafe) f.get( null );
ます。
Unsafe
定義により、「安全でない」です。これは少しごまかしです。
getDeclaredField
Linux x64上のJDK 8u131でのトリックを使用した動作を確認しましhs_err_pid*.log
たSIGSEGV
。
Unsafe
はチートではありません。OPはプログラミングの問題に対する「クリーン」な解決策を探していません。最悪の方法でクラッシュするには、jvmが必要です。厄介なネイティブのことを行うことがそれを可能にするものであり、まさにそれが行うことUnsafe
です。
情熱的なプログラマーでもこの質問に出くわしたので、ここに来ましたChad Fowlerによる。コピーにアクセスできない人のために、質問は「本当に優れたJavaプログラマー」を必要とする職位について面接する候補者に対する一種のフィルター/テストとして構成されています。
具体的には、彼は尋ねます:
純粋なJavaで、Java仮想マシンをクラッシュさせるプログラムをどのように作成しますか?
15年以上Javaでプログラミングしてきましたが、この質問は不可解で不公平であることがわかりました。他の人が指摘したように、マネージ言語としてのJavaは、クラッシュしないように特別に設計されています。もちろん、JVMのバグは常にありますが、
他の人が述べたように、JNIを介したいくつかのネイティブコードは、JREをクラッシュさせる確実な方法です。しかし、著者は特に純粋な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
か、同様の例外が発生しますが、これも実際にはクラッシュではありません。
だから何が残っていますか?筆者が適切な解決策として本当に心に留めていたことを聞きたいです。
更新:Chad Fowler がここで応答しました。
PS:それは他の点では素晴らしい本です。Rubyを学びながら、道徳的なサポートを得るためにそれを手に入れました。
このコードは厄介な方法でJVMをクラッシュさせます
import sun.dc.pr.PathDasher;
public class Crash
{
public static void main(String[] args)
{
PathDasher dasher = new PathDasher(null) ;
}
}
InternalError
はJDK 1.8でスローされます。JVMは失敗しなくなりました。
私がこれを試した最後の時間はそれをするでしょう:
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をクラッシュさせたい場合-Sun JDK 1.6_23以下で以下を使用します。
Double.parseDouble("2.2250738585072012e-308");
これは、Sun JDKのバグが原因です-OpenJDKにもあります。これは、Oracle JDK 1.6_24以降で修正されています。
Jon Meyer 著のJava Virtual Machineには、JVMをコアダンプさせる一連のバイトコード命令の例が含まれています。この本のコピーが見つかりません。誰かが持っている場合は、それを調べて回答を投稿してください。
winxpsp2 w / wmp10 jre6.0_7
Desktop.open(uriToAviOrMpgFile)
これにより、生成されたスレッドがキャッチされていないThrowableをスローし、ホットスポットをクラッシュさせます
YMMV
ハードウェアが壊れると、プログラムがクラッシュする可能性があります。私はかつて、特定のマシン上で再現可能な方法でアプリをクラッシュさせたが、まったく同じ設定で他のマシン上で問題なく動作した。マシンに欠陥のあるRAMがあったことがわかりました。
最短の方法:)
public class Crash
{
public static void main(String[] args)
{
main(args);
}
}
Exception in thread "main" java.lang.StackOverflowError at Test.main
。私はjdk1.8.0_65を使用しています
JVMがコアダンプ(つまり、クラッシュ)する原因の詳細な説明は次のとおりです。http: //kb.adobe.com/selfservice/viewContent.do?externalId = tn_17534
処理できない状況(つまり、Java例外またはエラーがない)のためにプロセスの異常終了としてクラッシュを定義した場合、これはJava内から実行できません(sun.misc.Unsafeクラスを使用する権限がない場合)。これがマネージコードの要点です。
ネイティブコードでの通常のクラッシュは、間違ったメモリ領域(nullアドレスまたはミスアライメント)へのポインタを逆参照することで発生します。別の原因としては、不正な機械命令(オペコード)や、ライブラリまたはカーネルコールからの未処理の信号が考えられます。JVMまたはシステムライブラリにバグがある場合、どちらもトリガーできます。
たとえば、JITされた(生成された)コード、ネイティブメソッド、またはシステムコール(グラフィックスドライバー)は、実際のクラッシュにつながる問題を抱えている可能性があります(ZIP関数を使用していてメモリが不足すると、クラッシュが発生することはよくありました)。これらの場合、JVMのクラッシュハンドラーが起動し、状態をダンプします。また、OSコアファイル(Windowsではワトソン博士、* nixではコアダンプ)を生成することもできます。
Linux / Unixでは、実行中のプロセスにシグナルを送信することにより、JVMを簡単にクラッシュさせることができます。注:SIGSEGV
Hotspotがこの信号をキャッチし、ほとんどの場所でNullPointerExceptionとして再度スローするため、これを使用しないでください。したがってSIGBUS
、たとえばを送信することをお勧めします。
より多くのスレッドを生成するスレッドプロセス(より多くのスレッドを生成する...)を作成すると、最終的には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:
#
「クラッシュ」とは、JVM がhs_err_pid%p.logに書き出されるなど、JVMの突然の中止を意味する場合は、この方法で実行できます。
-Xmx argを小さな値に設定し、メモリ不足で強制的にクラッシュするようにJVMに指示します。
-Xmx10m -XX:+CrashOnOutOfMemoryError
明確にするために、上記の2番目の引数がないと、jvm がOutOfMemoryErrorで終了するだけですが、「クラッシュ」したり、jvmを突然中止したりすることはありません。
この手法は、JVM -XX:ErrorFile引数をテストしようとしたときに役立ちました。これは、このようなhs_err_pidログを書き込む場所を制御します。そのようなクラッシュを強制する方法を見つけようとしているときに、私はこの投稿をここで見つけました。上記が私のニーズに最も簡単に機能することが後でわかったとき、私はそれをここのリストに追加したいと思いました。
最後に、FWIW、argsに-Xms値が(上記よりも大きい値に)設定されているときに誰かがこれをテストする可能性がある場合は、それも削除または変更する必要があります。そうしないと、クラッシュは発生しませんが、単純にjvmの起動に失敗し、「初期ヒープサイズが最大ヒープサイズより大きい値に設定されています」と報告されます。(JVMを一部のアプリサーバーなどでサービスとして実行している場合、それは明らかではありません。繰り返しますが、私はそれを私に噛み付けたので、共有したいと思いました。)
私は今それをやっていますが、方法は完全にはわかりません... :-) JVM(と私のアプリ)が完全に消えることがあります。エラーはスローされず、何も記録されません。警告なしで、すぐに作業状態からまったく実行されない状態になります。
最短?Robotクラスを使用してCTRL + BREAKをトリガーします。コンソールを閉じずにプログラムを閉じようとしたときに、これを見つけました(「終了」機能はありませんでした)。
これは重要ですか?
long pid = ProcessHandle.current().pid();
try { Runtime.getRuntime().exec("kill -9 "+pid); } catch (Exception e) {}
LinuxおよびJava 9以降でのみ機能します。
何らかの理由でProcessHandle.current().destroyForcibly();
、JVMを取得できず、JVMを強制終了せず、現在のプロセスの破棄が許可されていないjava.lang.IllegalStateException
というメッセージをスローします。
「クラッシュ」が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
}
だから、それはクラッシュの種類に依存します!?
ArithmeticException
ている