java - 有关堆栈跟踪中行号的文档

标签 java stack-trace

是否有关于 Java 堆栈跟踪行号的明确文档?
打印堆栈跟踪时如何“计算”它们(其背后的逻辑,而不是实现)?

为了向您展示我为什么感到困惑,请看下面的代码片段:

public static void main(String[] args) {
        String evilString = null;
        System.out.println(new StringBuilder()
                .append(evilString.toLowerCase()));
        evilString.toUpperCase();
    }

它给出: 线程“main”中的异常 java.lang.NullPointerException 在 be.company.training.ocjp6.App.main(App.java:28)

而下面这段代码:

public static void main(String[] args) {
        String evilString = null;
        System.out.println(new StringBuilder()
                .append("".toLowerCase()));
        evilString.toUpperCase();
    }

给出: 线程“main”中的异常 java.lang.NullPointerException 在 be.company.training.ocjp6.App.main(App.java:30)

所以我知道运行 StringBuilder 方法链会使它被视为 1 行(StringBuilder 代码在我的编辑器中从第 28 行开始)。但是,如果错误发生在 evilString.toUpperCase() 片段中,我们将回到第 30 行的正轨。

我想知道这样当我看到堆栈跟踪时,我可以确定在哪一行发生了错误(链接方法(在多行上)在我正在查看的代码中很常见)。

最佳答案

@kdgregory 指出,这似乎是依赖于编译器的。

这是我的 java 版本:

java version "1.6.0_29"
Java(TM) SE Runtime Environment (build 1.6.0_29-b11-402-10M3527)
Java HotSpot(TM) Client VM (build 20.4-b02-402, mixed mode)

使用此代码,我在第 9 行的每个堆栈跟踪(与源中的物理行号匹配)进行 NPE

public static void main(String[] args) { 
    String evilString = null;
    System.out.println(new StringBuilder()
        .append(
                evilString.toLowerCase()));  // <--- NPE here (line 9)
}

所以我使用 javap 进行了更深入的挖掘:

这是 main 的行号表,如 javap -l 所示

(行号表显示源代码行:指令偏移量

public static void main(java.lang.String[]);
LineNumberTable: 
line 6: 0
line 7: 2
line 9: 12
line 8: 16
line 7: 19
line 10: 22

源代码第 9 行从偏移量 12 开始。

javap -c 反汇编显示:

public static void main(java.lang.String[]);
Code:
0:  aconst_null
1:  astore_1
2:  getstatic   #16; //Field java/lang/System.out:Ljava/io/PrintStream;
5:  new #22; //class java/lang/StringBuilder
8:  dup
9:  invokespecial   #24; //Method java/lang/StringBuilder."<init>":()V
12: aload_1                                                    <--- closest line in the line number table
13: invokevirtual   #25; //Method java/lang/String.toLowerCase:()Ljava/lang/String;       <--- NPE here
16: invokevirtual   #31; //Method java/lang/StringBuilder.append:      (Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual   #35; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
22: return

我的猜测: 当在偏移量 13 处的 invokevirtual 处命中异常时,jvm 查找行号表中最近的先前条目并将其放入堆栈跟踪中。

关于java - 有关堆栈跟踪中行号的文档,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8702427/

相关文章:

java - 如何为处理其他异常时抛出的异常获取正确链接的堆栈跟踪?

java - 调试 : Mergesort

Java简单计算器错误

logging - 将结果堆栈跟踪默认写入文件

tomcat - 实时获取 J2EE Http 请求的堆栈跟踪

ios - 如何获取导致崩溃的类和方法名称?

java - 如何找到小于另一个元素的元素?

java - 从本地主机上的 Java 调用时,Php exec 无法正常运行

Java、Jacob 和 Microsoft Outlook 事件 : Receiving "Can' t find event iid"Error

android - 格式化异常消息以包含 Google Analytics for Android 中的整个堆栈跟踪?