Java StringBuilder最有效的初始容量大小?

Java StringBuilder最有效的初始容量大小?,java,memory,stringbuilder,Java,Memory,Stringbuilder,我正在写很多东西来记录突发事件,并优化数据路径。我使用StringBuilder构建日志文本。在内存管理方面,什么是最有效的初始容量,这样无论JVM如何,它都能正常工作?目标是避免几乎总是重新分配,这应该由大约80-100的初始容量来覆盖。但我也希望浪费尽可能少的字节,因为StringBuilder实例可能会挂在缓冲区中,浪费的字节会突然出现 我意识到这取决于JVM,但应该有一些值,这将浪费最少的字节,无论JVM是什么,都是“最小公分母”。我目前使用的是128-16,其中128是一个很好的整数,

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

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


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

在这种情况下,不要试图聪明

我目前使用128-16,其中128是一个很好的整数,减法是分配开销

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

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


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

好吧,最后我自己简单地测试了一下,然后在注释后测试了一些,以得到这个编辑过的答案

使用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字节。换句话说,分配1000000个初始容量为1..4的实例比分配相同数量的初始容量为5..8的实例要少8兆字节的内存(每个安装8字节)。

这个问题的答案取决于很多因素,例如,您在
StringBuilder
等中存储的文本长度。唯一的方法是使用内存和/或CPU探查器进行测量。没有理由担心几个字节,除非您正在创建成千上万的
StringBuilder
对象。到目前为止,最大的开销是IO成本。除非您不打算将此数据写入IO,否则我不会担心。您介意分享您的测试过程吗?-如何确定具有如此粒度的堆使用率?我手头没有代码,但StringBuilder初始容量每增加4个单位,堆使用率就会增加一步,然后在再次以4的倍数跳跃之前,接下来的3个大小的堆使用率大致相同。但那是4个字符,意思是8个字节,对吗?感谢您的提问,我明天肯定会再次测试以验证这一点。因此您观察到堆使用率以1000000 x 4字节的步长增加了?--我不敢估计一个[数据结构]将占用多少字节的Java堆空间,不是针对
char
,也不是针对任何Java程序中的任何其他值/类型。-此外,无论堆的分配粒度如何,GC决定将内存释放回堆的粒度是未知的,并且会影响任何度量。-如果您出于好奇和/或为了测量给定JVM的某些特性而进行测试,请继续。-否则。。。见我上面的答案:)我观察到1000000 x
newstringbuilder(112)
占用的堆容量与1000000 x
newstringbuilder(115)
差不多。将容量增加到116显著增加了堆使用,120再次增加了堆使用,等等。我非常惊讶地认为它是4个字节,但4个字符=8个字节更有意义(在64位JVM上)。