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