什么是 jvm 预分配异常?

What are jvm pre-allocated exceptions?

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

但在查找时,我只看到有关缺少堆栈跟踪的信息。 什么是 JVM 分配的异常?看来是优化了。

它是如何工作的,它的权衡是什么?

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

Reading the release notes in your post: "The compiler in the server VM now provides correct stack backtraces for all "cold" built-in exceptions. For performance purposes, when such an exception is thrown a few times, the method may be recompiled. After recompilation, the compiler may choose a faster tactic using preallocated exceptions that do not provide a stack trace."

是的,这是一个优化。

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

这消除了每次发生时都以丢失堆栈跟踪信息为代价不断创建新异常的需要。

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

删除此功能

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

当方法开始(隐式地)抛出这些异常之一时 too frequently,JVM 会注意到这一点,并将每次抛出时的异常分配替换为抛出已经预先分配的异常,而无需堆栈跟踪。

此机制依赖于实现,因此如果我们谈论热点,您可以在 graphKit.cpp:

中找到这些异常的列表
NullPointerException 
ArithmeticException
ArrayIndexOutOfBoundsException
ArrayStoreException
ClassCastException

理由很简单:抛出异常最昂贵的部分不是实际的抛出和堆栈展开,而是在异常中创建堆栈跟踪(这是对 VM 的相对较慢的调用,并且发生在异常构造函数中 Throwable#fillInStackTrace).要查找具体数字和相对成本,您可以阅读热点性能工程师关于 exceptional performance.

的精彩文章

有些人将异常用于常规控制流(请不要那样做)或出于性能考虑(这通常是不正确的,例如参见 [​​=17=] 一种流行的连接池框架),所以热点使这个[可能不好] 通过在没有堆栈跟踪的情况下抛出已经创建的异常来加快代码速度(因此消除了抛出最昂贵的部分)。

这种方法的缺点是现在您有无堆栈跟踪的异常。这没什么大不了的:如果这些隐式异常被频繁抛出,您可能不会使用它们的堆栈跟踪。但是,如果这个假设不正确,您将在日志中看到没有痕迹的异常。为防止这种情况,您可以使用 -XX:-OmitStackTraceInFastThrow