猿问

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

我想知道 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 开发人员以外的任何人都没有用时?


提前感谢任何能给我一些见解的人。


繁华开满天机
浏览 145回答 1
1回答

紫衣仙女

但是 JVM 怎么知道我在第 8 行崩溃了呢?看一下构造函数java.lang.Throwable:public Throwable() {&nbsp; &nbsp; fillInStackTrace();}该fillInStackTrace方法使用在 JVM 本身中实现的本机代码填充当前堆栈跟踪。堆栈跟踪本身只是一个 数组StackTraceElement,每个数组都包含代码路径中的类、方法、文件名和行号,我们可以通过它们创建异常。然后堆栈跟踪存储在Throwable实例中,稍后可以打印。顺便说一句,您可以创建一个Throwable并获取其堆栈跟踪,而无需实际抛出它。所以下面的代码:public class Foo {&nbsp; &nbsp; public static void main(String[] args) {&nbsp; &nbsp; &nbsp; &nbsp; Throwable t = new Throwable();&nbsp; &nbsp; &nbsp; &nbsp; for (StackTraceElement e : t.getStackTrace()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; System.out.println(e);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; System.out.println("This is the end of main()");&nbsp; &nbsp; }}将打印: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使用“内部”先决条件实用程序来检查边界。
随时随地看视频慕课网APP

相关分类

Java
我要回答