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 编译器 可以 优化掉一些空测试。例如:
- 对
this
的方法调用不能给出 NPE。
如果p
不是volatile,你这样写:
if (p != null) { p.something(); }
那么,p.something()
中隐含的空检查就不需要了。
如果p
不是volatile,你这样写:
p.something();
p.somethingElse();
然后不需要第二次隐式空检查。
还值得注意的是,空测试可能对具有深度管道的 CPU 的性能影响为零。这将取决于本地化的内存访问模式,以及编译器/硬件是否能够安排测试指令与(比如)内存读取或存储重叠。
JVM 可以使用虚拟内存硬件实现空检查。 JVM 安排它的虚拟地址 space 中的零页被映射到不可读 + 不可写的页。由于 null
表示为零,当 Java 代码尝试取消引用 null
时,这将尝试访问不可寻址的页面并导致 OS 传递 "segfault" 给 JVM 的信号。 JVM 的段错误信号处理程序可以捕捉到这一点,找出代码正在执行的位置,并在适当线程的堆栈上创建和抛出 NPE。
这很复杂而且相当昂贵。但是,只要 NPE 在应用程序中很少发生,费用就无关紧要。
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 编译器 可以 优化掉一些空测试。例如:
- 对
this
的方法调用不能给出 NPE。 如果
p
不是volatile,你这样写:if (p != null) { p.something(); }
那么,
p.something()
中隐含的空检查就不需要了。如果
p
不是volatile,你这样写:p.something(); p.somethingElse();
然后不需要第二次隐式空检查。
还值得注意的是,空测试可能对具有深度管道的 CPU 的性能影响为零。这将取决于本地化的内存访问模式,以及编译器/硬件是否能够安排测试指令与(比如)内存读取或存储重叠。
- 对
JVM 可以使用虚拟内存硬件实现空检查。 JVM 安排它的虚拟地址 space 中的零页被映射到不可读 + 不可写的页。由于
null
表示为零,当 Java 代码尝试取消引用null
时,这将尝试访问不可寻址的页面并导致 OS 传递 "segfault" 给 JVM 的信号。 JVM 的段错误信号处理程序可以捕捉到这一点,找出代码正在执行的位置,并在适当线程的堆栈上创建和抛出 NPE。这很复杂而且相当昂贵。但是,只要 NPE 在应用程序中很少发生,费用就无关紧要。