为了账号安全,请及时绑定邮箱和手机立即绑定

JVM怎么知道程序在哪一行抛出异常呢?

JVM怎么知道程序在哪一行抛出异常呢?

繁华开满天机 2023-06-08 17:43:04
我想知道 JVM 是如何检测崩溃的,具体来说,它是如何知道它在哪一行代码上崩溃的。这是代码的示例部分:import java.util.ArrayList;class Main {  public static void main(String[] args) {    ArrayList<String> crashMe = new ArrayList<String>(0);    crashMe.get(1);  }}这是崩溃消息(OpenJDK 10.0.2 通过repl.it):    Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 0    at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)    at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)    at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)    at java.base/java.util.Objects.checkIndex(Objects.java:372)    at java.base/java.util.ArrayList.get(ArrayList.java:458)    at Main.main(Main.java:8)到目前为止所有预期的行为。但是 JVM 怎么知道我在第 8 行崩溃了呢?编译java代码时是否忽略新行等?为什么 jdk.internal 包甚至抛出异常,当它们对 JVM 开发人员以外的任何人都没有用时?提前感谢任何能给我一些见解的人。
查看完整描述

1 回答

?
紫衣仙女

TA贡献1839条经验 获得超15个赞

但是 JVM 怎么知道我在第 8 行崩溃了呢?


看一下构造函数java.lang.Throwable:


public Throwable() {

    fillInStackTrace();

}

该fillInStackTrace方法使用在 JVM 本身中实现的本机代码填充当前堆栈跟踪。堆栈跟踪本身只是一个 数组StackTraceElement,每个数组都包含代码路径中的类、方法、文件名和行号,我们可以通过它们创建异常。然后堆栈跟踪存储在Throwable实例中,稍后可以打印。


顺便说一句,您可以创建一个Throwable并获取其堆栈跟踪,而无需实际抛出它。所以下面的代码:


public class Foo {

    public static void main(String[] args) {

        Throwable t = new Throwable();

        for (StackTraceElement e : t.getStackTrace()) {

            System.out.println(e);

        }

        System.out.println("This is the end of main()");

    }

}

将打印:


Foo.main(Foo.java:4)

This is the end of main()

请注意,这This is the end of main()是打印出来的,因为我们刚刚创建了一个异常。我们没有扔掉它。这就是启用从编译代码创建堆栈跟踪的原因。


编译java代码时是否忽略新行等?


什么时候编译?是的。创建堆栈跟踪时?否。字节码包含翻译成该字节码的源代码指令的行号。


为什么 jdk.internal 包甚至抛出异常,当它们对 JVM 开发人员以外的任何人都没有用时?


首先,JVM开发者也是人。他们应该像其他人一样有例外。


其次,您看到的异常似乎确实起源jdk.internal.util,但这只是因为ArrayList使用“内部”先决条件实用程序来检查边界。


查看完整回答
反对 回复 2023-06-08
  • 1 回答
  • 0 关注
  • 144 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信