5

我正在写很多东西来登录突发,并优化数据路径。我用 构建日志文本StringBuilder。什么是最有效的初始容量,内存管理明智的,所以不管JVM如何它都能很好地工作?目标是几乎总是避免重新分配,这应该由大约 80-100 的初始容量覆盖。但我也希望尽可能少地浪费字节,因为 StringBuilder 实例可能会在缓冲区中徘徊并且浪费的字节突然出现。

我意识到这取决于 JVM,但应该有一些价值,这将浪费最少的字节,不管 JVM,有点“最小公分母”。我目前正在使用128-16,其中 128 是一个不错的整数,减法用于分配开销。此外,这可能被认为是“过早优化”的情况,但由于我所追求的答案是“经验法则”数字,因此知道它在未来也会很有用。

我不期待“我最好的猜测”答案(我自己上面的答案已经是那个),我希望有人已经对此进行了研究并且可以分享基于知识的答案。

4

2 回答 2

4

在这种情况下不要试图变得聪明。

我目前使用的是 128-16,其中 128 是一个不错的整数,减法用于分配开销。

在 Java 中,这是基于对 JVM 内部工作的完全任意假设。Java 不是 C。字节对齐等绝对不是程序员可以或应该尝试利用的问题。

如果您知道字符串的(可能)最大长度,则可以将其用于初始大小。除此之外,任何优化尝试都是徒劳的。

如果你真的知道你的大量StringBuilders 会存在很长一段时间(这不太符合日志记录的概念),并且你真的觉得有必要尝试说服 JVM 节省一些字节的堆空间,你可能会trimToSize()在字符串完全构建后尝试使用。但是,再一次,只要你的字符串不浪费每个兆字节,你真的应该去关注应用程序中的其他问题。

于 2012-11-13T12:48:36.530 回答
3

好吧,我最终自己对此进行了简短的测试,然后在评论后进行了更多测试,以获得这个经过编辑的答案。

使用 JDK 1.7.0_07 和测试应用程序报告 VM 名称“Java HotSpot(TM) 64-Bit Server VM”,StringBuilder内存使用粒度为 4 个字符,甚至增加 4 个字符。

答:至少在这个 64 位 JVM 上,从内存分配的角度来看,任何 4 的倍数对于 StringBuilder 来说都是同样好的容量。

通过创建 1000000 个具有不同初始容量的 StringBuilder 对象进行测试,在不同的测试程序执行中(具有相同的初始堆状态),并在ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed()之前和之后打印出来。

打印出堆大小也证实了,实际上从堆中为每个StringBuilder缓冲区分配的数量是 8 个字节的偶数倍,正如预期的那样,因为 Java char 是 2 个字节长。换句话说,分配初始容量为 1..4 的 1000000 个实例比分配初始容量为 5...8 的相同数量的实例少大约 8 兆字节的内存(每个实例 8 字节)。

于 2012-11-13T13:52:22.340 回答