什么是jvm预分配例外?

时间:2017-02-08 14:05:54

标签: java performance jvm jvm-hotspot

我在那里看到对预先分配的JVM异常的引用: - http://www.oracle.com/technetwork/java/javase/relnotes-139183.html - http://dev.clojure.org/display/community/Project+Ideas+2016

但是我只能看到有关丢失堆栈跟踪的信息。 什么是JVM分配的异常?这似乎是一种优化。

它是如何运作的,以及它的权衡取舍?

2 个答案:

答案 0 :(得分:10)

这些是在JVM开始时预先分配的异常。 预分配的异常应该是隐式:它们是由JVM引发的,而不是throw new ...在发生意外情况时抛出:取消引用空指针,访问具有负索引的数组等。

当方法开始(隐式地)抛出其中一个异常too frequently时,JVM会注意到并且在抛出已经预分配的异常而没有堆栈跟踪的情况下替换每次抛出的异常分配。

此机制取决于实现,因此,如果我们正在讨论热点,您可以在graphKit.cpp中找到这些例外的列表:

NullPointerException 
ArithmeticException
ArrayIndexOutOfBoundsException
ArrayStoreException
ClassCastException

基本原理非常简单:抛出异常最昂贵的部分不是实际的抛出和堆栈展开,而是在异常中创建堆栈跟踪(它是对VM的相对较慢的调用,并且通过{发生在异常构造函数中) {1}})。要查找具体数字和相对成本,您可以阅读热点性能工程师关于exceptional performance的精彩文章。

有些人使用常规控制流程的异常(请不要这样做)或出于性能考虑(通常是不正确的,例如参见this有点流行的连接池框架),所以hotspot会这样做[可能很糟糕]代码通过抛出已经创建的异常而没有堆栈跟踪更快一些(因此抛弃了最昂贵的部分)。

这种方法的缺点是现在你有无堆栈跟踪异常。这不是什么大问题:如果经常抛出这些隐含的异常,你可能不会使用他们的堆栈跟踪。但是,如果这个假设不正确,那么您的日志中将没有跟踪的异常。为防止这种情况,您可以使用Throwable#fillInStackTrace

答案 1 :(得分:2)

您发布的发行说明解释了该功能:

  

阅读帖子中的发行说明:"服务器VM中的编译器现在为所有" cold"提供正确的堆栈回溯。内置异常。 出于性能目的,当抛出这样的异常几次时,可以重新编译该方法。重新编译之后,编译器可以使用不提供堆栈跟踪的预分配异常来选择更快的策略。"

是的,这是一项优化。

为了提高异常处理的速度,可能会预先分配经常抛出的异常。

这样就不需要每次发生新的异常,而是以丢失堆栈跟踪信息为代价。

您可以使用标记-XX:-OmitStackTraceInFastThrow

删除此功能