为什么Java不告诉你哪个指针是空的?
2022-09-01 12:41:59
我一直想知道为什么JVM在抛出时不告诉你哪个指针(或者更确切地说,哪个变量)是空的。NullPointerException
行号不够具体,因为有问题的行通常可能包含许多可能导致错误的变量。
是否有任何编译器或 JVM 标志可以使这些异常消息更有用?
我一直想知道为什么JVM在抛出时不告诉你哪个指针(或者更确切地说,哪个变量)是空的。NullPointerException
行号不够具体,因为有问题的行通常可能包含许多可能导致错误的变量。
是否有任何编译器或 JVM 标志可以使这些异常消息更有用?
这是因为取消引用总是在没有可用名称时发生。该值将加载到操作数堆栈上,然后传递到取消引用的 JRE 操作码之一。但是,操作数堆栈没有要与 null 值关联的名称。它所拥有的只是“空”。使用一些聪明的运行时跟踪代码,可以派生一个名称,但这会增加有限价值的开销。
因此,没有 JRE 选项可以为空指针异常打开额外信息。
在此示例中,引用存储在映射到局部变量名称的本地槽 1 中。但是取消引用发生在 invokevirtual 指令中,该指令只在堆栈上看到一个“null”值,然后引发异常:
15 aload_1
16 invokevirtual #5
同样有效的是数组加载后跟取消引用,但在这种情况下,没有名称映射到“null”值,只是另一个值的索引。
76 aload 5
78 iconst_0
79 aaload
80 invokevirtual #5
您也无法将名称静态分配给每个指令 - 此示例生成大量字节码,但您可以看到取消引用指令将接收 objA 或 objB,并且您需要动态跟踪此名称以报告正确的字节码,因为这两个变量都流向相同的取消引用指令:
(myflag ? objA : objB).toString()
对代码进行 JIT 后,它只是本机指针数学,如果本机代码中的任何指针为 null,则会引发异常。将该程序集反转回原始变量会产生毁灭性的性能影响,并且考虑到JIT将生成的代码优化到不同的级别,这通常甚至是不可能的。