How to Crash Java VM

How to Crash Java VM

 

最近线上Java应用爆出了个很诡异的问题,需要理解Java虚拟机方面的知识,也正在补充JVM方面的知识;突然有个想法,如何人为的让JVM爆掉(Crash)呢?

这个想法说起来简单,实际上想考虑完全还是比较困难的。我将我自己想到的内容先放上来,后面会补充一些其它的知识。

 

1:利用JVM里面的一些非常规错误(Error),如StackOverflowErrorOutOfMemoryError等。这个算是让虚拟机Crash的比较弱的条件,并不能算是JVM底层的问题,但是我们让JVM成功down掉了。

 

我们先看下StackOverflowError的情况:出现这种情况是因为虚拟机栈对于迭代深度有限制,当分配不足时,就会出现这个错误。

public class StackOverFlowCrash {

    /**
     * @param args
     */
    public static void main ( String[] args ) {
        // TODO Auto-generated method stub
        main(args);
    }

}

 出现异常:Exception in thread "main" java.lang.StackOverflowError

该问题出现的原因是当调用函数时,会将这个函数信息放到这个线程的栈中,只要这个方法没有返回,这个栈就一直存在。如果方法的嵌套层次调用太多,导致超过栈设置大小,就产生StackOverflowError溢出异常。

 

实际上在使用栈空间不足时,都会产生这个StackOverflowError问题,如启用新线程时,如果栈空间不足就会出问题;或者在Native Method中申请超大内存时,也会产生这个Error问题。

public class OOMCrash {

    /**
     * @param args
     */
    public static void main ( String[] args ) {
        // TODO Auto-generated method stub
        Object[] obj = new Object[Integer.MAX_VALUE];
    }
    public static void stackOverflow(){
        
    }

}

Exception in thread "main" java.lang.OutOfMemoryError: Requested array size exceeds VM limit

这个比较常见,就是申请的内存超过JVM的限制,就会导致OutOfMemoryError问题。

 

方法区内存溢出

方法区是用于存放Java的类相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等;在类加载器完成class文件加载的时候,会将这些信息放到方法区。如果方法区的内存占用达到最大值(-XX:MaxPermSize),就会抛出OOM异常,导致虚拟机Crash掉。

这种情况的测试思路比较简单,就是在运行区产生大量的类去填充方法区,直到方法区溢出为止。可以借助CGLib实现,动态生成类。

 

2JNI方法

如果调用JNI方法时出现异常,或者JNI代码中Crash掉的话,JVM也会相应的Crash掉。

  

3Security相关的Crash,使用反射可以调用JVM的本地方法资源,这样也可以导致JVM Crash掉。

import sun.misc.Unsafe;
public class UnsafeCrash {
    /**
     * @param args
     */
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    public static void crash() {
        unsafe.putAddress(0, 0);
    }
    public static void main(String[] args) {
        crash();
    }
}

执行后可以看下下面的异常,是SecurityException,同样会让JVM不能正常工作。

java.lang.ExceptionInInitializerError

Caused by: java.lang.SecurityException: Unsafe

 

3JVM(Native Code) bug

JVM本身也是个应用,其代码也有bug,如果能找到jvm本身的bug,应该就能使得JVM Crash掉。

 

这里有个很经典的实例,利用了JVM本身的bug

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

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

执行后会产生一个JVM Crash掉的信息:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_STACK_OVERFLOW (0xc00000fd) at pc=0x000000006dc3f414, pid=15928, tid=15708
#
# JRE version: 6.0_20-b02
# Java VM: Java HotSpot(TM) 64-Bit Server VM (16.3-b01 mixed mode windows-amd64 )
# Problematic frame:
# V  [jvm.dll+0x3af414]
#
# An error report file with more information is saved as:
# D:\workspace\jvmcrash\hs_err_pid15928.log

bug问题比较严重,出现EXCEPTION_STACK_OVERFLOW提示,同时在应用目录下产生hs_err_pidXYZ.log。比较根本的原因是GC过程的栈信息出现Overflow问题,导致JVM Crash掉。该问题在1.6版本中存在,在1.7中出现了OOMError,并不会导致虚拟机本身出现问题,出现异常提示的原因也有不一样。

  

JVMbug还可以看下这个实例:

import sun.dc.pr.PathDasher;

public class PathDasherCrash {

    /**
     * @param args
     */
    public static void main ( String[] args ) {
        PathDasher dasher = new PathDasher(null);
    }
}

 

该方法执行后也会产生异常:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000006dab3975, pid=16500, tid=15796
#
# JRE version: 6.0_20-b02
# Java VM: Java HotSpot(TM) 64-Bit Server VM (16.3-b01 mixed mode windows-amd64 )
# Problematic frame:
# V  [jvm.dll+0x223975]
#
# An error report file with more information is saved as:
# D:\workspace\jvmcrash\hs_err_pid16500.log
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
#

 注意是EXCEPTION_ACCESS_VIOLATION异常,这个异常的产生有多个方面的原因。

1:调用非安全方法

2JVM对于传入参数的处理有问题

3:该类中的方法大部分是native方法,JVM调用的native方法中对于null参数的处理不正确。

 

根据以上的思路,JNISecurity MethodJVM bugs等方面都可以导致JVM不能正常运行。

不过导致的方法不一样,在Java中还有一些其它的表现如ByteBufferDirect内存分配超过限制、编译器bug(http://seanhe.iteye.com/blog/905997)等。

 

 

这个也算是从反向思路来学习Java Virtual Machine吧。在http://stackoverflow.com上有个关于这个话题的讨论,大家可以系统学习下,不过内容也不离本文;大家对于这个问题本身的讨论(JVMCrash概念)比较有意思,这个可以仔细看下。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值