Java 如何使JVM崩溃?

Java 如何使JVM崩溃?,java,jvm,Java,Jvm,我在读一本关于编程技巧的书,其中作者问被采访者,“如何使JVM崩溃?”我认为可以通过编写一个最终会耗尽所有内存的无限for循环来实现这一点 有人知道吗?。事实上,对于JNI,崩溃是默认的操作模式。你必须加倍努力才能让它不崩溃。这取决于你所说的崩溃是什么意思 您可以执行无限递归以使其耗尽堆栈空间,但这将“优雅地”崩溃。您将得到一个异常,但JVM本身将处理所有事情 您还可以使用JNI调用本机代码。如果你做得不好,那么你可以让它很难崩溃。调试这些崩溃是“有趣的”(相信我,我必须写一个大的C++ DLL

我在读一本关于编程技巧的书,其中作者问被采访者,“如何使JVM崩溃?”我认为可以通过编写一个最终会耗尽所有内存的无限for循环来实现这一点


有人知道吗?

。事实上,对于JNI,崩溃是默认的操作模式。你必须加倍努力才能让它不崩溃。

这取决于你所说的崩溃是什么意思

您可以执行无限递归以使其耗尽堆栈空间,但这将“优雅地”崩溃。您将得到一个异常,但JVM本身将处理所有事情


您还可以使用JNI调用本机代码。如果你做得不好,那么你可以让它很难崩溃。调试这些崩溃是“有趣的”(相信我,我必须写一个大的C++ DLL,我们从一个签名的java applet调用)。p> 如果将无限for循环更改为对同一函数的递归调用,则会出现堆栈溢出异常:

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

public void causeStackOverflow() {
    causeStackOverflow();
}

最接近单个“答案”的是
System.exit()
,它在没有适当清理的情况下立即终止JVM。但除此之外,本机代码和资源耗尽是最有可能的答案。或者,您可以查看Sun的bug跟踪器,查找JVM版本中的bug,其中一些允许重复的崩溃场景。在32位版本(我们现在通常使用64位)下,当接近4GB内存限制时,我们通常会出现半常规崩溃。

完美的JVM实现永远不会崩溃

要使JVM崩溃,除了JNI之外,还需要在VM本身中找到一个bug。无限循环只会消耗CPU。无限分配内存只会导致构建良好的JVM中出现OutOfMemoryError。这可能会给其他线程带来问题,但是一个好的JVM仍然不应该崩溃


如果您可以在VM的源代码中发现一个bug,例如导致VM实现的内存使用出现分段错误,那么您实际上可以使它崩溃。

Jon Meyer的书中有一个导致JVM核心转储的一系列字节码指令的示例。我找不到这本书的副本。如果有人有一个,请查找并发布答案。

我不会说抛出OutOfMemoryError或StackOverflowerError或崩溃。这些只是正常的例外。要真正使VM崩溃,有3种方法:

  • 在本机代码中使用JNI和崩溃
  • 如果未安装安全管理器,则可以使用反射使VM崩溃。这是特定于VM的,但通常VM在私有字段中存储一组指向本机资源的指针(例如,指向本机线程对象的指针存储在java.lang.thread中的长字段中)。只要通过反射更改它们,VM迟早会崩溃
  • 所有虚拟机都有bug,所以您只需触发一个
  • 对于最后一种方法,我有一个简短的示例,它将使Sun Hotspot VM崩溃:

    public class Crash {
        public static void main(String[] args) {
            Object[] o = null;
    
            while (true) {
                o = new Object[] {o};
            }
        }
    }
    

    这会导致GC中的堆栈溢出,因此您不会得到StackOverflowerError,而是会得到一个包含hs_err*文件的真正崩溃。

    如果您将崩溃定义为由于未处理的情况(即没有Java异常或错误)而导致的进程中止,则这无法从Java内部完成(除非您有权使用sun.misc.Unsafe类)。这就是托管代码的全部要点

    本机代码中的典型崩溃是通过取消引用指向错误内存区域(空地址或错误对齐)的指针而发生的。另一个来源可能是非法的机器指令(操作码)或来自库或内核调用的未处理信号。如果JVM或系统库有bug,则两者都会被触发

    例如,JITed(生成的)代码、本机方法或系统调用(图形驱动程序)可能存在导致实际崩溃的问题(当您使用ZIP函数并且它们的内存不足时,崩溃是很常见的)。在这些情况下,JVM的崩溃处理程序启动并转储状态。它还可以生成一个OS核心文件(Windows上的Watson博士和*nix上的core dump)


    在Linux/Unix上,通过向正在运行的进程发送信号,可以很容易地使JVM崩溃。注意:您不应该为此使用
    SIGSEGV
    ,因为Hotspot捕获此信号,并在大多数地方将其作为NullPointerException重新抛出。因此,最好在winxpsp2 w/wmp10 jre6.0_7上发送一个
    SIGBUS

    Desktop.open(uriToAviOrMpgFile)

    这会导致生成的线程抛出一个未捕获的Throwable并崩溃


    YMMV

    以下是导致JVM核心转储(即崩溃)的详细说明:

    我现在正在做,但不完全确定如何…:-)JVM(和我的应用程序)有时完全消失了。没有抛出错误,没有记录任何内容。在没有任何警告的情况下立即从工作状态变为根本不运行。

    如果您想假装内存不足,可以这样做

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

    我知道有两种方法可以通过调用本机方法(内置的方法)导致JVM转储错误文件,但最好是您不知道如何执行此操作。;)

    JNI是崩溃的一个主要来源。您还可以使用JVMTI接口崩溃,因为它也需要用C/C++编写。

    损坏的硬件可能会使任何程序崩溃。我曾经在一台特定的机器上复制了一个应用程序崩溃,而在其他具有完全相同设置的机器上运行良好。结果表明机器的RAM有故障。

    使用以下方法:

    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:。撞车

    编辑:带有pushy建议的简化版本:

    Field f = Unsafe.class.getDeclaredField("theUnsafe");
    f.setAccessible(true);
    Unsafe unsafe = (Unsafe) f.get(null);
    unsafe.putAddress(0, 0);
    

    这段代码将以令人讨厌的方式使JVM崩溃

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

    如果要使JVM崩溃,请在Sun JDK 1.6_23或以下版本中使用以下命令:

    Double.parseDouble("2.2250738585072012e-308");
    
    这是由于在Sun JDK中出现了一个错误—也可以在OpenJDK中找到。
    这是从Oracle JDK 1.6_24开始修复的。

    我来这里是因为我在Chad Fowler的文章中也遇到了这个问题。对于无法访问副本的用户
    $ echo 'crap crap crap' > crap.class
    $ java crap
    Exception in thread "main" java.lang.ClassFormatError: Incompatible magic value 1668440432 in class file crap
    
    public class Crash
    {
        public static void main(String[] args)
        {
            main(args);
        }
    }
    
    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
    
    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
      }
    
    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();
        }
    }
    
    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:
    # 
    
    long pid = ProcessHandle.current().pid();
    try { Runtime.getRuntime().exec("kill -9 "+pid); } catch (Exception e) {}
    
     -Xmx10m -XX:+CrashOnOutOfMemoryError