Java 空指针检查顺序

Java 空指针检查顺序,java,jvm,java-memory-model,Java,Jvm,Java Memory Model,这些代码来自: 我无法理解作者用(****)突出显示的注释是什么意思。我认为他试图尽早生成NullPointerException。也就是说:如果此时h1或h2为空,则赋值h1.trap=0将抛出NPE 下面几行解释了为什么这会有帮助: 这样做可以使编译器从移动h1.a和h2.a加载中解放出来——我认为这与编译器所做的一些优化和JIT有关 最简单的方法是编写一个测试类,并在尝试访问传递的变量值时生成字节码,而在不访问时生成字节码并看到差异 或者你可以联系作者:Aleksey Shipilev(

这些代码来自:


我无法理解作者用(****)突出显示的注释是什么意思。

我认为他试图尽早生成
NullPointerException
。也就是说:如果此时
h1
h2
为空,则赋值
h1.trap=0
将抛出NPE

下面几行解释了为什么这会有帮助:

这样做可以使编译器从移动h1.a和h2.a加载中解放出来
——我认为这与编译器所做的一些优化和JIT有关

最简单的方法是编写一个测试类,并在尝试访问传递的变量值时生成字节码,而在不访问时生成字节码并看到差异

或者你可以联系作者:Aleksey Shipilev(shade)@Aleksey Shipilev

如果你真的想理解,我想你需要读一些关于这方面的东西:


Java规范要求在轮询实例的字段之前,即使没有显式NPE检查,也要检查实例的
h1
h2
是否为空-此功能也称为隐式空指针检查。让我们看看汇编代码(由JIT生成):

其中,取消引用空指针将导致向进程发送SEGV信号。VM有一个SEGV处理程序可以处理这个问题,并抛出一个适当的NullPointerException(NPE)


这可以被看作是一个小编译器的障碍,它可以阻止一些优化,在这些优化中,异常应该恰好在发生异常的地方抛出。此检查保证进一步执行代码不会导致NPE,因此编译器可以移动
h1.a
h2.a
加载,因为它不必再维护异常顺序。

@aleksey shipilev,您能对此发表评论吗?
public class ReadAfterReadTest {
    private final Holder h1 = new Holder();
    private final Holder h2 = h1;
    private static class Holder {
        int a;
        int trap;
    }
    @Actor
    public void actor1() {
        h1.a = 1;
    }
    @Actor
    public void actor2(II_Result r) {
        Holder h1 = this.h1;
        Holder h2 = this.h2;
        (*****)
        // Spam null-pointer check folding: try to step on NPEs early.
        // Doing this early frees compiler from moving h1.a and h2.a loads
        // around, because it would not have to maintain exception order anymore.
        (*****)
        h1.trap = 0;
        h2.trap = 0;

        // Spam alias analysis: the code effectively reads the same field twice,
        // but compiler does not know (h1 == h2) (i.e. does not check it, as
        // this is not a profitable opt for real code), so it issues two independent
        // loads.
        r.r1 = h1.a;
        r.r2 = h2.a;
    }
}
0x00007f1fad2429f2: mov    %rbx,0x18(%rsp)
0x00007f1fad2429f7: mov    (%rsp),%rbx
0x00007f1fad2429fb: mov    0x10(%rsp),%rcx
0x00007f1fad242a00: mov    0x28(%rsp),%r10    ;*aload
0x00007f1fad242a05: mov    0x10(%rbx),%r11d   ;*getfield h1
0x00007f1fad242a09: mov    0xc(%r11),%edx     ;*getfield a
                                              ; implicit exception: dispatches to 0x00007f1fad242b37
0x00007f1fad242a0d: mov    %r12d,0x10(%r11)   ;*putfield trap
0x00007f1fad242a11: mov    0x14(%rbx),%r9d    ;*getfield h2
0x00007f1fad242a15: mov    %r12d,0x10(%r9)    ;*putfield trap
                                              ; implicit exception: dispatches to 0x00007f1fad242b49
0x00007f1fad242a19: mov    %r10,0x28(%rsp)
0x00007f1fad242a1e: mov    %rcx,0x10(%rsp)