在Java程序中,当需要分配数千个类似大小的对象时,(在我看来)最好有一个“池”(这是一个单独的分配),其中包含可以从中提取的保留项需要的时候。这个单一的大型分配不会将堆分割成数千个较小的分配。
显然,没有办法专门将对象引用指向内存中的地址(对于其成员字段)来设置池。即使新对象引用了池的某个区域,仍然需要分配对象本身。如果不诉诸本机OS库,您将如何处理这样的许多分配?
答案 0 :(得分:5)
您可以尝试使用Commons Pool库。
那就是说,除非我有证据证明JVM没有按照我的要求行事,否则我可能会推迟优化对象创建。
答案 1 :(得分:1)
不要担心。除非您对正在运行的实际代码进行了大量测试和分析,并且知道垃圾收集存在问题并且JVM做得不够好,否则请将时间花在其他地方。
答案 2 :(得分:1)
如果您正在构建一个应用程序,其中可预测的响应时间非常重要,那么对象的汇集,无论它们多么小,都会为您带来红利。同样,池化也是您尝试汇集的数据集的大小以及您的计算机具有多少物理内存的因素。
有足够的proof on the web表明对象池,无论对象有多小,都有利于应用程序性能。
您可以执行两个级别的池:
这通常是应用程序设计决策。
此外,在多线程应用程序中,您希望对将要分配和返回池的不同线程数量敏感。您当然不希望您的应用程序因争用而陷入困境 - 特别是如果您同时处理数千个对象。
答案 3 :(得分:0)
人们常常认为GC是导致高性能Java应用程序性能低下的罪魁祸首,在修复它之后,只需将其留在那里,而不实际分析应用程序的内存行为。注意,虽然未缓存的存储器指令本质上比算术指令更昂贵(并且由于存储器访问< - >计算间隙而变得越来越昂贵)。因此,如果你关心性能,你当然应该关心内存管理。
支持缓存或更通用的面向数据的编程是在诸如游戏或移动应用程序(以降低功耗)等多种应用程序中实现高性能的关键。
Here是DOP上的SO线程。
Here是来自索尼R& D部门的幻灯片,展示了应用于PlayStation游戏的DOP的有用性(需要高性能)。
那么如何解决Java的问题,一般不允许你分配一块内存?我的猜测是,当程序刚刚启动时,您可以假设已经分配的页面中几乎没有内部碎片。如果你现在有一个分配数千或数百万个对象的循环,它们可能都是尽可能连续的。请注意,您只需要确保连续对象在同一个高速缓存行上延伸,在许多现代系统中,该高速缓存行只有64个字节。另外,如果您真的关心应用程序的(内存)性能,请查看DOP幻灯片。
简而言之:始终一次分配多个对象(增加分配的时间局部性),并且,如果GC已进行碎片整理,请事先运行它,否则尝试将此类分配减少到程序的开头。
我希望,这有一些帮助, -Domi
PS:@Dave,公共池库不会连续分配对象。它只是通过将它们放入引用数组,嵌入堆栈,链表或类似数据中来跟踪分配。