JVM 如何知道何时抛出 NullPointerException

How does the JVM know when to throw a NullPointerException

Java 虚拟机如何知道何时抛出 NullPointerException?如果对象为空,它是否会在我调用对象的每个方法之前检查它是否必须抛出 NullPointerException?如果是这样,这不是很慢吗?

NULLPointerException 基本上是一个 运行 时间异常,即 JVM 期望在您执行任何操作时引用实际对象。

为了更好地理解这一点,您需要知道如何在 java.Here 中创建和引用对象的语法是: myClass o = new myClass();

在这种情况下,在堆 space 中创建了一个对象,其中 o 作为对该对象的引用,即 o 基本上指向该对象。在 运行 时间内,JVM 确定 o 指向的实际对象并使用它来执行操作。

所以假设你有一个方法 doSomething() 作为上面 myClass 定义的实例方法,你像这样调用它 o.doSomething(),所以 JVM 会找到实际的对象并调用这个方法。

但是如果你设置 o = 空;那么 o 没有指向 myclass 的实际对象,即 o 没有指向任何东西。 所以现在在 o.doSomething 的执行期间,JVM 发现 o 没有指向任何东西,并在这种情况下抛出 运行time 异常 NULLPointerException。

它并不慢,因为它是 JVM 的设计方式,可以对发生在 运行 的实际引用对象进行操作,并且如果您没有在程序中正确处理 NULL 检查并且 NULLpointerException 被由 JVM 抛出然后您的程序崩溃并且 jvm 终止。

有关详细信息,请参阅 java 文档: http://docs.oracle.com/javase/7/docs/api/java/lang/NullPointerException.html

JVM 可以使用两种方法来 "detect" 空值。

  • JVM 可以在使用引用之前显式测试引用的值。这代表了开销,但 JIT 编译器 可以 优化掉一些空测试。例如:

    1. this 的方法调用不能给出 NPE。
    2. 如果p不是volatile,你这样写:

      if (p != null) { p.something(); }
      

      那么,p.something() 中隐含的空检查就不需要了。

    3. 如果p不是volatile,你这样写:

      p.something();
      p.somethingElse();
      

      然后不需要第二次隐式空检查。

    还值得注意的是,空测试可能对具有深度管道的 CPU 的性能影响为零。这将取决于本地化的内存访问模式,以及编译器/硬件是否能够安排测试指令与(比如)内存读取或存储重叠。

  • JVM 可以使用虚拟内存硬件实现空检查。 JVM 安排它的虚拟地址 space 中的零页被映射到不可读 + 不可写的页。由于 null 表示为零,当 Java 代码尝试取消引用 null 时,这将尝试访问不可寻址的页面并导致 OS 传递 "segfault" 给 JVM 的信号。 JVM 的段错误信号处理程序可以捕捉到这一点,找出代码正在执行的位置,并在适当线程的堆栈上创建和抛出 NPE。

    这很复杂而且相当昂贵。但是,只要 NPE 在应用程序中很少发生,费用就无关紧要。