你如何崩溃一个JVM?

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

有人有什么想法吗?

最接近单个“答案”的是System.exit() ,它会立即终止JVM而不进行正确的清理。 但除此之外,本地代码和资源耗尽是最可能的答案。 或者,您可以在Sun的bug跟踪器上查看您的JVM,版本中的错误JVM,其中一些错误允许可重复的崩溃情况。 在32-bit版本(我们现在通常使用'64 32-bit ')接近4 Gb内存限制时,我们习惯了半规则的崩溃。

我不会抛出一个OutOfMemoryError或StackOverflowError崩溃。 这只是正常的例外。 要真正让虚拟机崩溃,有三种方法:

  1. 在本地代码中使用JNI并崩溃。
  2. 如果没有安装安全pipe理器,则可以使用reflection来使VM崩溃。 这是虚拟机的具体情况,但通常情况下,虚拟机在私有字段中存储一堆指向本机资源的指针(例如,指向本地线程对象的指针存储在java.lang.Thread的长字段中)。 只要通过reflection来改变它们,虚拟机迟早会崩溃。
  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 *文件的实际崩溃。

JNI 。 实际上,用JNI,crashing是默认的操作模式。 你必须加倍努力才能让它不会崩溃。

用这个:

 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(); } } 

这个类必须在启动类path上,因为它使用的是受信任的代码,所以像这样运行:

java -Xbootclasspath / p :. 紧急

我来到这里是因为我也在Chad Fowler的“激情程序员”中遇到过这个问题。 对于那些无法获得副本的人来说,这个问题被定义为一种面试候选人的筛选/testing,要求“真正优秀的Java程序员”。

具体来说,他问:

你将如何编写一个程序,在纯Java中,这将导致Java虚拟机崩溃?

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

  1. 经过15年以上的生产级JRE,这是罕见的。
  2. 任何这样的错误都可能在下一个版本中被修补,那么作为程序员的你是否有可能遇到并回忆当前JRE展示瓶塞的细节?

正如其他人所说,通过JNI的一些本地代码是一个肯定的方式来崩溃一个JRE。 但是作者在纯Java中特别提到,所以没有了。

另一种select是提供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本身没有坠毁; 它正确地检测到伪代码,报告并退出。

这给我们留下了最明显的解决scheme,比如通过recursion来堆栈,通过对象分配耗尽堆内存,或者简单地抛出RuntimeException 。 但是这只会导致JRE退出时出现StackOverflowError或类似的exception,这也不是真正的崩溃

那剩下什么了? 我真的很想听听作者真正想到的是一个合适的解决scheme。

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

PS:这是一本非常棒的书。 学习Ruby的时候,我select了它来提供道义上的支持。

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

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

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

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

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

除了JNI之外,为了使JVM崩溃,你需要在虚拟机中find一个bug。 无限循环只消耗CPU。 无限分配的内存应该只是在一个精心构build的JVM中导致OutOfMemoryError。 这可能会导致其他线程的问题,但一个好的JVM仍然不应该崩溃。

如果您可以在虚拟机的源代码中发现一个错误,并且例如在虚拟机的内存使用情况中导致分段错误,那么您实际上可能会崩溃它。

取决于你的意思是崩溃。

你可以做一个无限recursion来使堆栈空间不足,但是会“优雅地”崩溃。 你会得到一个exception,但JVM本身将处理一切。

您也可以使用JNI来调用本地代码。 如果你不这样做,那么你可以让它崩溃。 debugging这些崩溃是“有趣”(相信我,我不得不写一个大的C ++ DLL,我们从一个签名的Java小程序调用)。 🙂

如果您想要使JVM崩溃 – 请在Sun JDK 1.6_23或更低版本中使用以下内容:

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

这是由于Sun JDK中的一个错误 – 也在OpenJDK中发现。 这是从Oracle JDK 1.6_24开始解决的。

在winxpsp2 w / wmp10 jre6.0_7

Desktop.open(uriToAviOrMpgFile)

这会导致一个产生的线程抛出未被捕获的Throwable并崩溃热点

因人而异

破碎的硬件可能会导致程序崩溃。 我曾经在特定的机器上重现过一次应用程序崩溃,同时在其他机器上运行正确的设置。 原来那台机器的内存有问题。

由Jon Meyer撰写的“ Java虚拟机 ”一书中有一系列字节码指令的例子,它们导致JVM进行核心转储。 我找不到我的这本书的副本。 如果有人有,请查看并发布答案。

这里是关于什么导致JVM核心转储(即崩溃)的详细解释: http : //kb.adobe.com/selfservice/viewContent.do?externalId=tn_17534

最短的方法:)

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

如果由于未处理的情况(即没有Javaexception或错误)将崩溃定义为进程中止,那么这不能从Java内部完成(除非您有权使用sun.misc.Unsafe类)。 这是托pipe代码的全部重点。

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

例如,JITed(生成)代码,本地方法或系统调用(graphics驱动程序)可能会导致真正的崩溃问题(使用ZIPfunction并且耗尽内存时很常见)。 在这种情况下,JVM的崩溃处理程序会启动并转储状态。 它也可以生成一个OS核心文件(Windows上的Dr.Watson和* nix上的核心转储)。

在Linux / Unix上,通过向运行进程发送一个信号,可以很容易地导致JVM崩溃。 注意:你不应该为此使用SIGSEGV ,因为Hotspot捕获这个信号并且在大多数地方将它重新抛出为NullPointerException。 因此,最好发送一个SIGBUS

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

您可以通过调用来暂停JVM

Runtime.getRuntime().halt( status )

根据文件: –

“这个方法不会导致closures钩子被启动,并且如果已经启用了exitization on exit,它将不运行未被取消的终结器。

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

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

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

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

我现在正在做,但不完全确定如何…… 🙂 JVM(和我的应用程序)有时只是完全消失。 没有错误抛出,没有logging。 没有任何警告,立即从工作转到不运行。

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

如果你创build一个线程进程,无限地产生更多的线程(产生更多的线程,…),你最终会导致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: # 

如果你改变那个无限的循环为recursion调用相同的函数,那么你会得到一个堆栈溢出exception:

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

如果“崩溃”是任何中断正常终止的jvm /程序,那么未处理的exception可以做到这一点。

 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 } 

那么,这取决于什么types的CRASH?!