您如何使JVM崩溃?


144

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

有人有主意吗?



stackoverflow.com/questions/30072883/… “如果我使用JDK1.8_40或更高版本(Oracle或OpenJDK相同),以下代码以及对话框调整大小将使应用程序崩溃(尝试使用Windows 7,x64、64位JDK)” -代码只有40行,这会导致JVM 正常崩溃
Dreamspace总裁

Answers:


6

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


71
没有适当的清理?你确定吗?该文档说:“通过启动其关闭顺序来终止当前正在运行的Java虚拟机...启动所有已注册的关闭钩子(如果有的话)...运行所有未调用的终结器”-这不是正确的清除方法吗?
user85421 2009年

51
这不会使JVM崩溃,而是有目的地明确地开始执行的有序关闭。
BenM

9
更接近崩溃的jvm是Runtime.getRuntime()。halt(status)。根据文档,“如果启用了退出时终结,则此方法不会导致启动关闭挂钩,也不会运行未调用的终结器”。仍然不是崩溃,而是比System.exit更近。
henry 2012年

48
这确实是一个错误的答案。
Antonio

174

我不会将抛出OutOfMemoryError或StackOverflowError称为崩溃。这些只是正常的例外。要使虚拟机真正崩溃,可以采用以下三种方法:

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


9
哇!这会使没有hs_err *文件但只有“分段错误!”的Sun Java 5,Sun Java 6和OpenJDK 6(在Ubuntu 9.04上)崩溃。...
Joachim Sauer

1
System.exit()是使JVM崩溃的更容易方法(除非安装了安全管理器)
Instantsetsuna 2010年

4
不知道什么时候修复的,只是在1.7.0_09中测试过就可以了。刚得到预期的结果:线程“ main”中的异常java.lang.OutOfMemoryError:CrashJVM.main(CrashJVM.java:7)的Java堆空间
乍得NB

2
我在Intel Core i7 2.4 GHz / 8 GB RAM / JDK1.7 64bit上尝试了上面的代码,但JVM在20分钟后仍然启动。(有趣:我的笔记本电脑风扇比空中的战斗机响亮)。JDK 1.7+中已解决此问题吗?
realPK

3
在JDK 1.8_u71这会导致java.lang.OutOfMemoryError: GC overhead limit exceeded
Clashsoft


56

用这个:

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:。崩溃


14
除了使用-Xbootclasspath之外,您还可以执行以下操作:Field f = Unsafe.class.getDeclaredField( "theUnsafe" ); f.setAccessible( true ); unsafe = (Unsafe) f.get( null );对我来说很棒。
pushy

Unsafe根据定义,“不安全”。这有点作弊。
热舔

1
确认getDeclaredField可以在Linux x64的JDK 8u131中使用技巧来进行工作,包括hs_err_pid*.log从中产生SIGSEGV
Jesse Glick

使用Unsafe不是欺骗。OP并未寻求针对编程问题的“干净”解决方案。他需要jvm以最丑陋的方式崩溃。做这种讨厌的事情是可以做到的,而事实正是Unsafe如此。
jvdneste

34

我之所以来到这里,是因为我也在Chad Fowler的《热情的程序员》中遇到了这个问题。对于那些无权获取副本的人,该问题被设计为一种筛选/测试,供求职者面试要求“真正优秀的Java程序员”的候选人。

具体来说,他问:

您将如何用纯Java编写程序,从而导致Java虚拟机崩溃?

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

  1. 经过15年以上的生产级JRE,这是罕见的。
  2. 下一个发行版中可能会修补任何此类错误,因此,作为程序员,您有多大可能会遇到并回忆起当前JRE展示停止器的详细信息?

正如其他人提到的那样,通过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类似的异常,这也不是真正的crash

那还剩下什么呢?我真的很想听听作者真正想到的是一个适当的解决方案。

更新:乍得福勒在这里回应

PS:这是本很棒的书。我在学习Ruby时出于道德上的支持而选择了它。


1
这样的面试问题是对Java开发人员的试金石,测试时间已经足够长:1)见证了(许多)JVM崩溃,以及2)得出了一些结论,或者更好的是,(自称)Java专家试图理解崩溃的根本原因。查德·福勒(Chad Fowler)在他的书中还指出,自称Java程序员“甚至无法提出错误的答案”,即没有尝试思考何时会出现一类潜在的问题。最重要的是:这个问题是“如何防止JVM崩溃?”的问题。显然更好。
Shonzilla 2012年

1
我会寻找只回答(像这里大多数人所做的那样)“堆栈溢出”,system.exit()或其他“正常”关闭的人,因为他们并不真正了解JVM或“崩溃”一词。识别(就像您所做的一样)这是非常异常的,这是识别更高级的程序员的一种很好的方法。我确实同意您的第一句话,我认为这是一个极好的且完全公平的问题,一个没有具体答案的问题总是最好的。
比尔K

20

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

import sun.dc.pr.PathDasher; 

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

1
使用带有此代码的JDK 1.7时出现编译错误: 访问限制:由于必需的库C:\ Program Files \ Java \ jdk1.7.0_51 \ jre \ lib \ rt.jar的限制,无法访问PathDasher类型
realPK

7
InternalError在JDK 1.8中引发。JVM不再失败。
Sotirios Delimanolis 2014年

18

上次我尝试这样做会做到:

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

考虑到这是展示如何仅使用Java代码完成操作的仅有的两个答案之一,并且包括完整的代码,我对此感到有些惊讶。
热门点击

我同意投票毫无必要-这是一次真正的崩溃,但是您将如何回答面试问题。除非您以前对此进行了研究和记忆,否则您将无法在面试中给出答案,如果可以的话,我还是会考虑中性至较差的答案-它不能说明您如何解决该问题。我希望您所做的是针对jvm bug的google搜索并实施,这是一个很好的答案。
比尔K

@BillK-不,以上内容完全是我自己的工作,尽管几年前我想出了它,并尝试了各种方法。在一次采访中,我可能会说:“我已经完成了,使用try / catch和递归,但是我现在无法听到确切的代码。”
热舔

1
详细信息(JDK版本,任何VM参数)是什么?不知道什么版本“ 11.2-b0”。我正在运行它,但是它只消耗大量CPU。
Stefan Reich,

@Hot Licks:JVM崩溃示例中的概念是什么?为何JVM会因代码崩溃而崩溃。所有线程都有单独的堆栈线程...
VJS

15

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

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

如果您可以在VM的源代码中找到一个错误,并且例如在VM的实现的内存使用中引起分段错误,那么您实际上可以将其崩溃。


14

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

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

这是由于Sun JDK中的一个错误 -也可以在OpenJDK中找到。自Oracle JDK 1.6_24起已修复此问题。


10

取决于崩溃的含义。

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

您还可以使用JNI调用本机代码。如果您做的不正确,则可能会使它崩溃。调试那些崩溃很“有趣”(相信我,我不得不编写一个很大的C ++ DLL,我们从一个已签名的Java applet中调用它)。:)


6

乔恩·迈耶(Jon Meyer)撰写的Java虚拟机一书中有一系列导致JVM进行核心转储的字节码指令示例。我找不到这本书的副本。如果外面有人,请查一下并发布答案。


5

在带有wmp10 jre6.0_7的winxpsp2上

Desktop.open(uriToAviOrMpgFile)

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

青年汽车


5

损坏的硬件可能会使任何程序崩溃。我曾经在特定计算机上可再现地崩溃了一个应用程序,而在其他计算机上却以完全相同的设置运行良好。原来这台机器的RAM有问题。


5

最短的方法:)

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
Quazi Irfan

5

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

您可以通过调用挂起JVM

Runtime.getRuntime().halt( status )

根据文档:

“如果启用了退出时终结,则此方法不会导致启动关闭挂钩,也不会运行未调用的终结器。”



4

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

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

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


4

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

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

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

在Linux / Unix上,您可以通过将信号发送给正在运行的进程来使JVM崩溃。注意:请勿使用SIGSEGV此方法,因为Hotspot会捕获此信号并将其作为NullPointerException再次抛出,在大多数情况下都是如此。因此最好发送一个SIGBUS例子。


3

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


2

如果创建的线程进程无限生成更多线程(生成更多线程,...),最终将导致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分钟后,观看您的ram)

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:
# 

1

如果“崩溃”是指JVM突然中止,例如会导致JVM将其写出到其hs_err_pid%p.log,则可以通过这种方式进行。

将-Xmx arg设置为一个很小的值,并告诉JVM在内存不足时强制崩溃:

 -Xmx10m -XX:+CrashOnOutOfMemoryError

需要明确的是,如果没有上面的第二个arg,它将导致jvm 终止以OutOfMemoryError,但是不会“崩溃”或突然中止jvm。

当我尝试测试JVM -XX:ErrorFile arg时,该技术被证明是有用的,该JVM控制应该在何处写入hs_err_pid日志。我在这里找到这篇文章,同时试图找到强制这种崩溃的方法。后来我发现上述方法最适合我的需求时,我想将其添加到此处的列表中。

最后,FWIW,如果有人在您的args中已经设置了-Xms值(大于上面的值)时可以对其进行测试,那么您也想删除或更改它,否则将不会崩溃,而只是jvm启动失败,报告“初始堆大小设置为大于最大堆大小的值”。(如果将JVM作为服务运行(例如与某些应用程序服务器一起使用),这并不明显。同样,它使我感到痛苦,所以我想共享它。)


0

如果将无限循环更改为对同一函数的递归调用,则将获得堆栈溢出异常:

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

public void causeStackOverflow() {
    causeStackOverflow();
}

0

我现在正在做,但是还不完全确定该怎么做... :-) JVM(和我的应用程序)有时会完全消失。没有引发错误,没有记录任何内容。从工作状态转变为完全不运行而没有任何警告。


开始检查硬件,尤其是内存!
托尔比约恩Ravn的安徒生

不幸的是,它在多台机器上运行正常。只能由一个特定的应用程序来完成(并且不占用大量内存或处理器)。
Brian Knoblauch

0

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


旧问题-希望将来有人从您的回答中受益。
dbmitch

0

这算吗?

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

尝试复制JVM崩溃时遇到此问题。

Jni可以工作,但是需要针对不同的平台进行调整。最终,我使用这种组合使JVM崩溃

  1. 使用此JVM选项启动应用程序 -XX:+CrashOnOutOfMemoryError
  2. 使用long[] l = new long[Integer.MAX_VALUE];触发OOM

然后,JVM将崩溃并生成崩溃日志。


-2

如果“崩溃”是会导致jvm /程序无法正常终止的任何事情,则可以通过Un-handled异常来完成。

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
  }

因此,取决于哪种类型的CRASH ?!


3
抛出异常并不是崩溃。
Quazi Irfan

但是,未处理的运行时异常是崩溃,ArithmeticException
中旬
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.