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

有人有什么想法吗?

有帮助吗?

解决方案

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

其他提示

我不会将抛出 OutOfMemoryError 或 StackOverflowError 称为崩溃。这些只是正常的例外情况。要真正使虚拟机崩溃,有 3 种方法:

  1. 使用 JNI 并在本机代码中崩溃。
  2. 如果未安装安全管理器,您可以使用反射来使虚拟机崩溃。这是特定于 VM 的,但通常 VM 会在私有字段中存储一堆指向本机资源的指针(例如指向本机线程对象的指针存储在一个长字段中 java.lang.Thread)。只要通过反射改变它们,虚拟机迟早会崩溃。
  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,崩溃是默认的操作模式。你必须加倍努力才能让它不崩溃。

用这个:

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:.碰撞

我来这里是因为我也遇到了这个问题 充满激情的程序员, ,查德·福勒着。对于那些无法获得副本的人来说,这个问题被认为是对面试需要“真正优秀的 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 或类似的异常,这又是 并不是真正的崩溃.

那么还剩下什么呢?我真的很想听听作者真正想要的正确解决方案。

更新:查德·福勒 在这里回复.

附:这是一本很棒的书。我在学习 Ruby 时选择它是为了精神上的支持。

这段代码会导致 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
#

---------------  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 实现永远不会崩溃。

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

如果您可以在虚拟机的源代码中找到错误,例如导致虚拟机实现的内存使用出现分段错误,那么您实际上可以使其崩溃。

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

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

这是由于一个 漏洞 在 Sun JDK 中 - 也可以在 OpenJDK 中找到。从 Oracle JDK 1.6_24 开始,此问题已得到修复。

取决于你所说的崩溃是什么意思。

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

您还可以使用 JNI 调用本机代码。如果你做得不好,那么你可能会使其严重崩溃。调试这些崩溃是“有趣的”(相信我,我必须编写一个大的 C++ DLL,我们从签名的 java 小程序中调用它)。:)

这本书 Java虚拟机 Jon Meyer 提供了一个导致 JVM 核心转储的一系列字节码指令的示例。我找不到这本书的副本。如果有人有,请查找并发布答案。

在 winxpsp2 上 w/wmp10 jre6.0_7

Desktop.open(uriToAviOrMpgFile)

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

青年MMV

损坏的硬件可能会使任何程序崩溃。我曾经遇到过一个应用程序在特定机器上可重复崩溃的情况,而在具有完全相同设置的其他机器上运行良好。结果发现那台机器的内存有故障。

最短的可能的方式:)

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

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

您可以通过调用来停止 JVM

Runtime.getRuntime().halt( status )

根据文档:-

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

这里详细解释了导致 JVM 核心转储的原因(即碰撞):http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_17534

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

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

例如,JITed(生成的)代码、本机方法或系统调用(图形驱动程序)可能会出现导致真正崩溃的问题(当您使用 ZIP 函数并且内存不足时发生崩溃是很常见的)。在这些情况下,JVM 的崩溃处理程序会启动并转储状态。它还可以生成操作系统核心文件(Dr.Windows 上的 Watson 和 *nix 上的核心转储)。

在 Linux/Unix 上,您可以通过向正在运行的进程发送信号轻松地使 JVM 崩溃。笔记:你不应该使用 SIGSEGV 为此,因为 Hotspot 会捕获此信号,并在大多数地方将其作为 NullPointerException 重新抛出。所以最好发送一个 SIGBUS 例如。

如果你想假装你的内存不足,你可以这样做

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

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

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

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

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

我现在正在做,但不完全确定如何...:-) JVM(和我的应用程序)有时会完全消失。没有抛出任何错误,也没有记录任何内容。在没有任何警告的情况下立即从工作变为根本不运行。

这算不算?

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 与消息 不允许破坏当前进程.

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

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

public void causeStackOverflow() {
    causeStackOverflow();
}

如果“崩溃”是任何中断 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
  }

那么,这取决于什么类型的崩溃?!

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top