在什么时候值得在Java中重用数组?
Java中的缓冲区需要多大才能值得重用?
或者,换句话说:我可以重复分配,使用和丢弃byte[]对象,或者运行一个池来保留和重用它们。我可能会分配很多经常被丢弃的小缓冲区,或者一些不被丢弃的大缓冲区。在什么规模上将它们集中起来比重新分配更便宜,小的分配与大的分配相比如何?
编辑:
好的,具体参数。假设英特尔酷睿2双核CPU,最新的VM版本,用于操作系统选择。这个问题并不像听起来那么模糊...一点代码和一个图表就可以回答它。
编辑2:
你已经发布了很多好的一般规则和讨论,但这个问题确实需要数字。发布他们(和代码)!理论是伟大的,但证据是数字。结果是否因系统而异并不重要,我只是在寻找一个粗略的估计(数量级)。似乎没有人知道性能差异是否会是1.1,2,10或100 +的因素,这是重要的事情。对于任何使用大型数组的Java代码来说,这都很重要 - 网络,生物信息学等。
获得良好基准的建议:
- 在基准测试中运行代码之前预热代码。所有方法都应至少调用
100010000 次,以获得完整的 JIT 优化。 - 确保基准测试方法至少运行
1 10秒,并尽可能使用 System.nanotime 来获得准确的计时。 - 在仅运行最少应用程序的系统上运行基准测试
- 运行基准测试 3-5 次并报告所有时间,因此我们可以看到它的一致性。
我知道这是一个模糊且有些苛刻的问题。我会定期检查这个问题,答案会得到评论并一致地评级。懒惰的答案不会(请参阅下面的标准)。如果我没有任何彻底的答案,我会附上赏金。无论如何,我可能会奖励一个非常好的答案,并增加一点。
我所知道的(不需要重复):
- Java 内存分配和 GC 速度更快,而且速度越来越快。
- 对象池曾经是一个很好的优化,但现在它大部分时间都会损害性能。
- 对象池“通常不是一个好主意,除非对象的创建成本很高。Yadda yadda.
我不知道的是:
- 我希望内存分配在标准现代 CPU 上运行的速度 (MB/s) 有多快?
- 分配大小如何影响分配率?
- 在池中,分配的数量/大小与重用的收支平衡点是什么?
路由到已接受的答案(越多越好):
- 最近的白皮书显示了现代CPU上的分配和GC数据(最近一年左右,JVM 1.6或更高版本)
- 代码为简洁和正确的微基准测试,我可以运行
- 解释分配如何影响绩效以及影响原因
- 测试这种优化的真实示例/轶事
背景:
我正在开发一个库,为Java添加LZF压缩支持。此库通过添加其他压缩级别(更多压缩)以及与 C LZF 库中的字节流的兼容性来扩展 H2 DBMS LZF 类。我正在考虑的一件事是,是否值得尝试重用用于压缩/解压缩流的固定大小的缓冲区。缓冲区可能是 ~8 kB 或 ~32 kB,在原始版本中,它们约为 128 kB。可以为每个流分配一次或多次缓冲区。我正在尝试弄清楚如何处理缓冲区以获得最佳性能,并着眼于未来潜在的多线程。
是的,如果有人有兴趣使用它,该库将作为开源发布。