4

我正在尝试快速编写一些东西,并且不断分配和释放内存,这使得分配内存的位置在性能方面很重要。

分配对象是否总是将它们分配到堆中?JIT 编译是否会进行任何形式的花哨分配优化?

4

2 回答 2

11

分配的对象new放在堆上,但 JIT/JVM可能会使用转义分析优化它们以堆栈。在 IBM developerWorks 上发表的这篇文章中阅读更多关于它的信息:

VM 可以使用一种称为逃逸分析的技术,通过这种技术,它们可以判断某些对象在其整个生命周期内都被限制在单个线程中,并且该生命周期受给定堆栈帧的生命周期的限制。这样的对象可以安全地分配在堆栈上而不是堆上。

您无法直接控制堆栈分配,就像您无法预测 GC 何时运行一样。如果您真的需要对内存机制进行如此深入的控制,唯一的方法就是使用 C/C++。

无论如何,在使您的软件过于复杂之前请三思而后行。我上面链接的论文的结论对内存管理非常清楚:

JVM 非常擅长找出我们过去认为只有开发人员才能知道的事情。通过让 JVM 根据具体情况在堆栈分配和堆分配之间进行选择,我们可以获得堆栈分配的性能优势,而不会让程序员为是在堆栈上分配还是在堆上分配而苦恼。

这并不意味着您永远不需要对内存进行细粒度控制,但在大多数情况下,JVM 可以比普通程序员更好地优化。

于 2013-05-12T09:39:21.417 回答
2

JLS 说new分配一个新对象。JLS 12.5:

“当评估类实例创建表达式(第 15.9 节)导致类被实例化时,会显式创建一个新类实例。”

JLS 没有说明对象的分配位置。如果编译器可以推断(通过转义分析)可达性规则允许在堆栈上分配对象,那么这是允许的。

JLS 通常被解读为允许优化,其效果不能通过观察程序的执行结果来检测。显然,Java 7 的最新版本执行的优化之一涉及优化异常创建/抛出/捕获代码并将其替换为无条件跳转语句(或类似......)。在某些情况下,这种优化涉及优化显式new语句。

总之,new表达式通常会导致堆分配,但有时对象是在堆栈上分配的,有时分配会被完全优化掉。

于 2013-05-12T11:02:22.113 回答