我正在读一本关于编程技巧的书,其中作者问受访者:“你如何崩溃JVM?”我认为你可以通过写一个最终耗尽所有内存的无限for循环来实现。
有人有任何想法吗?
答案 0 :(得分:171)
我不会调用抛出OutOfMemoryError或StackOverflowError崩溃。这些只是正常的例外。要真正崩溃虚拟机有三种方法:
对于最后一个方法,我有一个简短的例子,它会使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 *文件的真正崩溃。
答案 1 :(得分:122)
JNI。事实上,对于JNI,崩溃是默认的操作模式。你必须加倍努力才能让它不会崩溃。
答案 2 :(得分:55)
使用此:
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:。碰撞
答案 3 :(得分:31)
我来到这里是因为我也在The Passionate Programmer中遇到了Chad Fowler的问题。对于那些无法访问副本的人来说,这个问题被视为一种过滤器/测试,适用于需要“真正优秀的Java程序员”的职位的候选人。
具体来说,他问:
如何用纯Java编写一个会导致Java虚拟机崩溃的程序?
我用Java编程超过15年,我发现这个问题既困惑又不公平。正如其他人所指出的那样,Java作为托管语言专门设计为不会崩溃。当然总有JVM错误,但是:
正如其他人所提到的,通过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 responded here。
PS:这是一本非常棒的书。我在学习Ruby的过程中选择了道德支持。答案 4 :(得分:20)
此代码将以令人讨厌的方式崩溃JVM
import sun.dc.pr.PathDasher;
public class Crash
{
public static void main(String[] args)
{
PathDasher dasher = new PathDasher(null) ;
}
}
答案 5 :(得分:17)
上次我尝试过这样做:
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
答案 6 :(得分:14)
完美的JVM实现永远不会崩溃。
要使JVM崩溃,除了JNI之外,您还需要在VM本身找到一个错误。无限循环只消耗CPU。无限分配内存应该只是在一个构建良好的JVM中引起OutOfMemoryError。这可能会导致其他线程出现问题,但是一个好的JVM仍然不应该崩溃。
如果您可以在VM的源代码中发现错误,例如导致VM实现的内存使用中出现分段错误,那么您实际上可以将其崩溃。
答案 7 :(得分:13)
如果要使JVM崩溃 - 请在Sun JDK 1.6_23或更低版本中使用以下命令:
Double.parseDouble("2.2250738585072012e-308");
这是由于Sun JDK中的bug - 也可以在OpenJDK中找到。 这是从Oracle JDK 1.6_24开始修复的。
答案 8 :(得分:10)
取决于崩溃的意思。
你可以进行无限递归,使其耗尽堆栈空间,但这会“优雅地”崩溃“。你会得到一个例外,但JVM本身将处理所有事情。
您还可以使用JNI调用本机代码。如果你不这么做就可以让它崩溃。调试这些崩溃是“有趣的”(相信我,我必须编写一个我们从签名的java applet调用的大型C ++ DLL)。 :)
答案 9 :(得分:6)
Jon Meyer的书Java Virtual Machine有一系列字节码指令的例子,这些指令导致JVM进行核心转储。我找不到这本书的副本。如果那里有人有,请查阅并发布答案。
答案 10 :(得分:5)
破坏的硬件可能会导致任何程序崩溃。我曾经在特定的机器上重复出现应用程序崩溃,同时在其他机器上运行正常,具有完全相同的设置。事实证明该机器有错误的RAM。
答案 11 :(得分:5)
不是崩溃,而是比使用System.exit
您可以通过调用
来暂停JVM Runtime.getRuntime().halt( status )
根据文件: -
"此方法不会导致启动关闭挂钩,并且如果已启用“退出时终止”,则不会运行未读取的终结器"。
答案 12 :(得分:5)
最短的方式:)
public class Crash
{
public static void main(String[] args)
{
main(args);
}
}
答案 13 :(得分:5)
on winxpsp2 w / wmp10 jre6.0_7
Desktop.open(uriToAviOrMpgFile)
这会导致生成的线程抛出未捕获的Throwable并崩溃热点
YMMV
答案 14 :(得分:5)
与单个“答案”最接近的是System.exit()
,它会在没有正确清理的情况下立即终止JVM。但除此之外,本机代码和资源耗尽是最可能的答案。或者,您可以查看Sun的错误跟踪器,查找您的JVM版本中的错误,其中一些允许可重复的崩溃方案。在32位版本下接近4 Gb内存限制时,我们常常会发生半常规崩溃(我们现在通常使用64位)。
答案 15 :(得分:4)
这里详细解释了导致JVM核心转储(即崩溃)的原因: http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_17534
答案 16 :(得分:4)
如果由于未处理的情况(即没有Java异常或错误)将崩溃定义为进程中止,则无法在Java中执行此操作(除非您有权使用sun.misc.Unsafe类) 。这是托管代码的重点。
本机代码中的典型崩溃通过取消引用指向错误内存区域(空地址或未对齐)的指针而发生。另一个来源可能是非法机器指令(操作码)或来自库或内核调用的未处理信号。如果JVM或系统库存在错误,则可以触发两者。
例如,JITed(生成的)代码,本机方法或系统调用(图形驱动程序)可能会导致实际崩溃的问题(当您使用ZIP函数并且内存不足时,这种情况很常见)。在这些情况下,JVM的崩溃处理程序启动并转储状态。它还可以生成OS核心文件(Windows上的Dr. Watson和* nix上的核心转储)。
在Linux / Unix上,您可以通过向正在运行的进程发送Signal来轻松地使JVM崩溃。注意:您不应该使用SIGSEGV
,因为Hotspot捕获此信号并在大多数地方将其重新抛出为NullPointerException。因此,最好发送SIGBUS
为例。
答案 17 :(得分:3)
JNI是崩溃的重要来源。您也可以使用JVMTI接口崩溃,因为它也需要用C / C ++编写。
答案 18 :(得分:3)
如果您想假装内存不足,可以
public static void main(String[] args) {
throw new OutOfmemoryError();
}
我知道有两种方法可以通过调用本机方法(内置的方法)使JVM转储错误文件,但最好不要知道如何执行此操作。 ;)
答案 19 :(得分: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分钟后,看你的公羊)
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:
#
答案 20 :(得分:1)
最短?使用Robot类触发CTRL + BREAK。我在没有关闭控制台的情况下尝试关闭程序时发现了这一点(它没有'退出'功能)。
答案 21 :(得分:0)
我现在正在做,但不完全确定如何... :-) JVM(和我的应用程序)有时会完全消失。没有错误抛出,没有记录。在没有任何警告的情况下立即从工作到完全不运行。
答案 22 :(得分: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
并显示消息不允许破坏当前进程。
答案 23 :(得分:0)
如果“崩溃”是指JVM突然中止,例如会导致JVM将其写到hs_err_pid%p.log ,则可以这样做。
>将-Xmx arg设置为一个很小的值,并告诉JVM在内存不足时强制崩溃:
-Xmx10m -XX:+CrashOnOutOfMemoryError
要清楚,没有上面的第二个参数,它只会导致jvm 终止,并带有OutOfMemoryError,但不会“崩溃”或突然中止jvm。
当我尝试测试JVM -XX:ErrorFile arg时,该技术被证明是有用的,该JVM控制应在何处写入此类hs_err_pid日志。我在这里找到了这篇文章,同时试图找到强制这种崩溃的方法。后来我发现上述方法最适合我的需求时,我想将其添加到此处的列表中。
最后,FWIW,如果有人在您的参数中已经设置了-Xms值(大于上面的值)时可以对其进行测试,那么您也想删除或更改该值,否则将不会得到崩溃,但只是jvm启动失败,报告“初始堆大小设置为大于最大堆大小的值”。 (如果将JVM作为服务运行(例如与某些应用程序服务器一起使用,这并不明显。同样,它使我感到痛苦,所以我想共享它。)
答案 24 :(得分:0)
尝试复制JVM崩溃时遇到此问题。
Jni可以工作,但是需要针对不同的平台进行调整。 最终,我使用这种组合使JVM崩溃
-XX:+CrashOnOutOfMemoryError
long[] l = new long[Integer.MAX_VALUE];
触发OOM 然后,JVM将崩溃并生成崩溃日志。
答案 25 :(得分:-1)
如果将无限循环更改为对同一函数的递归调用,则会出现堆栈溢出异常:
public static void main(String[] args) {
causeStackOverflow();
}
public void causeStackOverflow() {
causeStackOverflow();
}
答案 26 :(得分:-2)
如果'崩溃'是任何中断jvm /程序正常终止的东西,然后一个未处理的异常可以做到这一点。
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?!