转载

如何把事情搞砸(合集) : 如何使Java虚拟机崩溃

最初见到这个问题是在《我编程,我快乐——程序员职业规划之道》上,我的第一反应是构造一个OutOfMemoryError或者StackOverflowError。为了快速产生结果,在JVM参数进行如下设置后:

-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 

下面的代码即可很快产生OutOfMemoryError:

import java.util.ArrayList; import java.util.List; public class Crash {  public static void main(String[] args) {   List<Object> list = new ArrayList<Object>();   while(true) {    list.add(new Object());   }  } }  

输出效果

[GC (Allocation Failure) [PSYoungGen: 7330K->992K(9216K)] 7330K->5297K(19456K), 0.0094021 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]  [GC (Allocation Failure) --[PSYoungGen: 9184K->9184K(9216K)] 13489K->19416K(19456K), 0.0171858 secs] [Times: user=0.06 sys=0.00, real=0.02 secs]  [Full GC (Ergonomics) [PSYoungGen: 9184K->0K(9216K)] [ParOldGen: 10232K->9893K(10240K)] 19416K->9893K(19456K), [Metaspace: 2524K->2524K(1056768K)], 0.1437797 secs] [Times: user=0.23 sys=0.00, real=0.14 secs]  [Full GC (Ergonomics) [PSYoungGen: 7706K->8077K(9216K)] [ParOldGen: 9893K->7783K(10240K)] 17600K->15860K(19456K), [Metaspace: 2524K->2524K(1056768K)], 0.1274782 secs] [Times: user=0.25 sys=0.00, real=0.13 secs]  [Full GC (Allocation Failure) [PSYoungGen: 8077K->8076K(9216K)] [ParOldGen: 7783K->7783K(10240K)] 15860K->15859K(19456K), [Metaspace: 2524K->2524K(1056768K)], 0.0685814 secs] [Times: user=0.16 sys=0.00, real=0.07 secs]  Exception in thread "main" java.lang.OutOfMemoryError: Java heap space  at java.util.Arrays.copyOf(Arrays.java:3210)  at java.util.Arrays.copyOf(Arrays.java:3181)  at java.util.ArrayList.grow(ArrayList.java:261)  at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)  at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)  at java.util.ArrayList.add(ArrayList.java:458)  at Demo.main(Demo.java:9) [Full GC (Ergonomics) [PSYoungGen: 8192K->0K(9216K)] [ParOldGen: 7783K->492K(10240K)] 15975K->492K(19456K), [Metaspace: 2550K->2550K(1056768K)], 0.0036032 secs] [Times: user=0.06 sys=0.00, real=0.00 secs]  Heap  PSYoungGen   total 9216K, used 164K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)   eden space 8192K, 2% used [0x00000000ff600000,0x00000000ff6290e8,0x00000000ffe00000)   from space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)   to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)  ParOldGen    total 10240K, used 492K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)   object space 10240K, 4% used [0x00000000fec00000,0x00000000fec7b000,0x00000000ff600000)  Metaspace    used 2557K, capacity 4486K, committed 4864K, reserved 1056768K   class space used 275K, capacity 386K, committed 512K, reserved 1048576K  

至于产生StackOverflowError,一个没有返回的递归函数即可实现。

但从某种意义上说,这些并没有让JVM崩溃,而是抛出一个异常,Java虚拟机规范里面已经明确定义了这些异常发生的情况。

在真正的黑客眼里,JVM内部的Bug才是他们的答案。不过JVM内部的Bug最终会被修复,对于一般爱好者,可以找找以前的Java Bug Database,然后用旧版本的JVM验证。

不过还有另外一种容易引起JVM崩溃的地方就是JNI,虽然是外部代码引起的,但应该也算是JVM机制上的一种缺陷吧。

以下演示一下JNI导致Java虚拟机崩溃的例子。语文学得不好,直接上代码:

JvmCrash.java

class JvmCrash {     public static native void greeting(); } 

JvmCrashTest.java

class JvmCrashTest {  public static void main(String[] args)  {   JvmCrash.greeting();  }  static  {   System.loadLibrary("JvmCrash");  } }  

JvmCrash.h (由javah工具自动生成的)

/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class JvmCrash */  #ifndef _Included_JvmCrash #define _Included_JvmCrash #ifdef __cplusplus extern "C" { #endif /*  * Class:     JvmCrash  * Method:    greeting  * Signature: ()V  */ JNIEXPORT void JNICALL Java_JvmCrash_greeting   (JNIEnv *, jclass);  #ifdef __cplusplus } #endif #endif 

JvmCrash.c

#include "JvmCrash.h" #include <stdio.h>  JNIEXPORT void JNICALL Java_JvmCrash_greeting(JNIEnv* env, jclass cl) {     printf("Hello Crash world!/n");     int i = 0;     int j = 1 / i; } 

然后,我们就能得到一个Fatal Error而不是一个Exception了!

# # A fatal error has been detected by the Java Runtime Environment: # #  EXCEPTION_INT_DIVIDE_BY_ZERO (0xc0000094) at pc=0x10001020, pid=2388, tid=4988 # # JRE version: Java(TM) SE Runtime Environment (8.0_40-b26) (build 1.8.0_40-b26) # Java VM: Java HotSpot(TM) Client VM (25.40-b25 mixed mode, sharing windows-x86 ) # Problematic frame: # C  [JvmCrash.dll+0x1020] # # Failed to write core dump. Minidumps are not enabled by default on client versions of Windows # # An error report file with more information is saved as: # C:/Documents and Settings/Administrator/workspace/JNICrash/hs_err_pid2388.log # # If you would like to submit a bug report, please visit: #   http://bugreport.java.com/bugreport/crash.jsp # The crash happened outside the Java Virtual Machine in native code. # See problematic frame for where to report the bug. # Hello Crash World!  
正文到此结束
Loading...