it-swarm.cn

你如何崩溃JVM?

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

有人有什么想法吗?

140
Shivasubramanian A

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

6
Leigh Caldwell

我不会调用抛出OutOfMemoryError或StackOverflowError崩溃。这些只是正常的例外。要真正崩溃VM有三种方法:

  1. 使用JNI并在本机代码中崩溃。
  2. 如果未安装任何安全管理器,则可以使用反射来崩溃VM。这是VM特定的,但通常VM存储一组指向私有字段中的本机资源的指针(例如,指向本机线程对象的指针存储在的长字段中Java.lang.Thread)。只需通过反射更改它们,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 *文件的真正崩溃。

171
ralfs

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

122
Dan Dyer

用这个:

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:。紧急

55
Dave Griffiths

我来到这里是因为我在 The Passionate Programmer ,Chad Fowler中遇到了这个问题。对于那些无法访问副本的人来说,这个问题被视为一种过滤器/测试,用于面试需要“真正优秀的Java程序员”的职位的候选人。

具体来说,他问:

你会如何用纯Java编写一个会导致Java虚拟机崩溃的程序?

我用Java编程超过15年,我发现这个问题既困惑又不公平。正如其他人所指出的那样,Java作为一种托管语言,是专门设计的不是崩溃。当然总有JVM错误,但是:

  1. 经过15年以上的生产级JRE,这种情况很少见。
  2. 任何这样的错误很可能会在下一个版本中修补,那么你作为程序员有多大可能遇到并回忆起当前JRE show-stoppers的细节?

正如其他人所提到的,通过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时,我选择了它以获得道德支持。

31
George Armhold

此代码将以令人讨厌的方式崩溃JVM

import Sun.dc.pr.PathDasher; 

public class Crash
{
     public static void main(String[] args)
     {    
        PathDasher dasher = new PathDasher(null) ;
     }
}
20
Rob Mayhew

上次我试过这个会这样做:

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
17
Hot Licks

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

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

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

14
Dave L.

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

Double.parseDouble("2.2250738585072012e-308");

这是由于Sun JDK中的 bug - 也可以在OpenJDK中找到。这是从Oracle JDK 1.6_24开始修复的。

13
Prabath Siriwardena

取决于崩溃的意思。

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

您还可以使用JNI调用本机代码。如果你不这么做就可以让它崩溃。调试那些崩溃是“有趣的”(相信我,我必须写一个大的C++ DLL,我们从一个签名的Java小程序调用)。 :)

10
Herms

这本书 Java虚拟机 由Jon Meyer提供了一系列字节码指令的例子,这些指令导致JVM进行核心转储。我找不到这本书的副本。如果有人有,请查阅并发布答案。

6
Soulfly

硬件损坏会导致任何程序崩溃。我曾经在特定的机器上重复出现应用程序崩溃,同时在其他机器上运行正常,具有完全相同的设置。事实证明该机器有错误的RAM。

5
Michael Borgwardt

不是崩溃,而是比使用System.exit的接受答案更接近崩溃

您可以通过调用来暂停JVM

Runtime.getRuntime().halt( status )

根据文件: -

“如果启用了finalization-on-exit,此方法不会导致启动关闭挂钩,也不会运行未启动的终结器”。

5
henry

最短的方式:)

public class Crash
{
    public static void main(String[] args)
    {
        main(args);
    }
}
5
RRM

在winxpsp2上w/wmp10 jre6.0_7

Desktop.open(uriToAviOrMpgFile)

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

因人而异

5
kitsuneymg

如果由于未处理的情况(即没有Java异常或错误)将崩溃定义为进程中止,则无法在Java中执行此操作(除非您有权使用Sun.misc.Unsafe类)。这是托管代码的重点。

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

例如,JITed(生成的)代码,本机方法或系统调用(图形驱动程序)可能会导致实际崩溃的问题(当您使用Zip函数并且内存不足时,通常会发生崩溃)。在这些情况下,JVM的崩溃处理程序启动并转储状态。它还可以生成操作系统核心文件(Windows上的Dr. Watson和* nix上的核心转储)。

在Linux/Unix上,您可以通过向正在运行的进程发送Signal来轻松地使JVM崩溃。注意:你不应该使用SIGSEGV,因为Hotspot捕获了这个信号并在大多数地方重新抛出它作为NullPointerException。所以最好发送一个SIGBUS例如。

4
eckes

以下是有关导致JVM核心转储(即崩溃)的原因的详细说明: http://kb.Adobe.com/selfservice/viewContent.do?externalId=tn_17534

4
COTOHA

如果你想假装你的内存耗尽,你可以做

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

我知道通过调用本机方法(内置的方法)导致JVM转储错误文件的几种方法,但它可能最好你不知道如何做到这一点。 ;)

3
Peter Lawrey

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

3
Jared

如果你创建一个无限生成更多线程的线程进程(产生更多线程,那......),你最终会在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:
# 
2
Lightfire228

最短?使用Robot类触发CTRL + BREAK。当我试图在不关闭控制台的情况下关闭我的程序时,我发现了这一点(它没有“退出”功能)。

1
user6022288

我现在正在做,但不完全确定如何... :-) JVM(和我的应用程序)有时会完全消失。没有错误抛出,没有记录。在没有任何警告的情况下立即从工作到完全不运行。

0
Brian Knoblauch

这算数了吗?

long pid = ProcessHandle.current().pid();
try { Runtime.getRuntime().exec("kill -9 "+pid); } catch (Exception e) {}

它仅适用于Linux和Java 9。

由于某种原因,我没有得到,ProcessHandle.current().destroyForcibly();没有杀死JVM并抛出Java.lang.IllegalStateException与消息 不允许当前进程的破坏

0
mszmurlo