我正在写很多东西来登录突发,并优化数据路径。我使用StringBuilder
构建日志文本。什么是最有效的初始容量,内存管理明智,所以无论JVM如何都能很好地工作?目标是避免几乎总是重新分配,这应该由大约80-100的初始容量覆盖。但我也想浪费尽可能少的字节,因为StringBuilder实例可能会在缓冲区中出现并且会浪费掉浪费的字节。
我意识到这取决于JVM,但是应该有一些值,这会浪费最少的字节,无论JVM,都是“最小公分母”。我目前正在使用128-16
,其中128是一个很好的整数,减法用于分配开销。此外,这可能被认为是“过早优化”的情况,但由于我所追求的答案是一个“经验法则”数字,因此知道它在将来也会有用。
我不期待“我最好的猜测”答案(上面我自己的答案已经是这样),我希望有人已经研究过这个并且可以分享基于知识的答案。
答案 0 :(得分:4)
在这种情况下,不要试图变聪明。
我目前正在使用128-16,其中128是一个很好的整数,减法用于分配开销。
在Java中,这是基于对JVM内部工作方式的完全随意的假设。 Java不是C.字节对齐等绝对不是不是程序员可以或应该尝试利用的问题。
如果您知道(可能的)字符串的最大长度,您可以将其用作初始大小。除此之外,任何优化尝试都是徒劳的。
如果你真的知道你的StringBuilder
大量存在很长时间(这不符合日志记录的概念),和你真的觉得有必要尝试说服JVM保存一些字节的堆空间,你可以尝试在完全构建字符串后使用trimToSize()
。但是,再一次,只要你的字符串不会浪费兆字节,你就应该专注于应用程序中的其他问题。
答案 1 :(得分:3)
好吧,我最后自己对此进行了简短的测试,然后在评论后再测试一下,以获得这个编辑过的答案。
使用JDK 1.7.0_07和测试应用报告虚拟机名称“Java HotSpot(TM)64位服务器虚拟机”,StringBuilder
内存使用量的粒度为4 字符,均匀增加4个字符。
答案: 4 的任何倍数从内存分配的角度来看同样适合StringBuilder,至少在这个64位JVM上是这样。
通过创建具有不同初始容量的1000000个StringBuilder对象,在不同的测试程序执行中(具有相同的初始堆状态),并在之前和之后打印出ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed()
来进行测试。
打印出堆大小也已确认,每个StringBuilder
缓冲区实际从堆中分配的数量是8个字节的偶数倍,正如预期的那样,因为Java char是2个字节长。换句话说,分配初始容量为1..4的1000000个实例需要大约8兆字节的内存(每个实例8个字节),而不是分配初始容量为5 ... 8的相同数量的数据。