我正在读一本关于编程技能的书,作者问受访者:“如何崩溃JVM?” 我认为您可以通过编写一个无限的for循环来这样做,最终将耗尽所有内存。
有人有主意吗?
我正在读一本关于编程技能的书,作者问受访者:“如何崩溃JVM?” 我认为您可以通过编写一个无限的for循环来这样做,最终将耗尽所有内存。
有人有主意吗?
Answers:
与单个“答案”最接近的是System.exit()
,它会在没有适当清理的情况下立即终止JVM。但是除此之外,最有可能的答案是本机代码和资源耗尽。另外,您可以在Sun的错误跟踪器中查找您的JVM版本中的错误,其中一些允许重复出现的崩溃情况。在32位版本下接近4 Gb内存限制时,我们通常会遇到半常规崩溃(现在通常使用64位)。
我不会将抛出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 *文件的真正崩溃。
java.lang.OutOfMemoryError: GC overhead limit exceeded
用这个:
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:。崩溃
Field f = Unsafe.class.getDeclaredField( "theUnsafe" ); f.setAccessible( true ); unsafe = (Unsafe) f.get( null );
对我来说很棒。
Unsafe
根据定义,“不安全”。这有点作弊。
getDeclaredField
可以在Linux x64的JDK 8u131中使用技巧来进行工作,包括hs_err_pid*.log
从中产生SIGSEGV
。
Unsafe
不是欺骗。OP并未寻求针对编程问题的“干净”解决方案。他需要jvm以最丑陋的方式崩溃。做这种讨厌的事情是可以做到的,而事实正是Unsafe
如此。
我之所以来到这里,是因为我也在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
类似的异常,这也不是真正的crash。
那还剩下什么呢?我真的很想听听作者真正想到的是一个适当的解决方案。
更新:乍得福勒在这里回应。
PS:这是本很棒的书。我在学习Ruby时出于道德上的支持而选择了它。
此代码将以令人讨厌的方式使JVM崩溃
import sun.dc.pr.PathDasher;
public class Crash
{
public static void main(String[] args)
{
PathDasher dasher = new PathDasher(null) ;
}
}
InternalError
在JDK 1.8中引发。JVM不再失败。
上次我尝试这样做会做到:
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
如果要使JVM崩溃-在Sun JDK 1.6_23或更低版本中使用以下命令:
Double.parseDouble("2.2250738585072012e-308");
这是由于Sun JDK中的一个错误 -也可以在OpenJDK中找到。自Oracle JDK 1.6_24起已修复此问题。
在带有wmp10 jre6.0_7的winxpsp2上
Desktop.open(uriToAviOrMpgFile)
这会导致生成的线程抛出未捕获的Throwable并导致热点崩溃
青年汽车
最短的方法:)
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
这是有关导致JVM核心转储(即崩溃)的原因的详细说明:http : //kb.adobe.com/selfservice/viewContent.do?externalId=tn_17534
如果将崩溃定义为由于未处理的情况(例如,没有Java异常或错误)而导致进程中止,则无法从Java内部完成(除非您有权使用sun.misc.Unsafe类)。这就是托管代码的重点。
本机代码中的典型崩溃是通过取消对错误内存区域(空地址或未对齐)的指针的引用而发生的。另一个来源可能是非法的机器指令(操作码)或来自库或内核调用的未处理信号。如果JVM或系统库中有错误,均可触发这两者。
例如,JIT(生成的)代码,本机方法或系统调用(图形驱动程序)可能会导致实际崩溃的问题(使用ZIP函数时崩溃很普遍,并且内存不足)。在这些情况下,JVM的崩溃处理程序将启动并转储状态。它还可以生成OS核心文件(Windows上为Watson博士,* nix上为核心转储)。
在Linux / Unix上,您可以通过将信号发送给正在运行的进程来使JVM崩溃。注意:请勿使用SIGSEGV
此方法,因为Hotspot会捕获此信号并将其作为NullPointerException再次抛出,在大多数情况下都是如此。因此最好发送一个SIGBUS
例子。
如果创建的线程进程无限生成更多线程(生成更多线程,...),最终将导致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:
#
如果“崩溃”是指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作为服务运行(例如与某些应用程序服务器一起使用),这并不明显。同样,它使我感到痛苦,所以我想共享它。)
我现在正在做,但是还不完全确定该怎么做... :-) JVM(和我的应用程序)有时会完全消失。没有引发错误,没有记录任何内容。从工作状态转变为完全不运行而没有任何警告。
如果“崩溃”是会导致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 ?!
ArithmeticException
即