【问题标题】:Most efficient initial capacity size for StringBuilder?StringBuilder 最有效的初始容量大小?
【发布时间】:2012-11-13 11:48:25
【问题描述】:

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

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

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

【问题讨论】:

  • 这个问题的答案取决于很多事情,例如您在StringBuilder 中存储的文本多长时间等。找出答案的唯一方法是使用内存和/或 CPU 分析器。除非您创建数十万个 StringBuilder 对象,否则没有理由担心几个字节。
  • 目前最大的开销是 IO 成本。除非您不打算将这些数据写入 IO,否则我不会担心。

标签: java memory stringbuilder


【解决方案1】:

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

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

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

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

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

【讨论】:

    【解决方案2】:

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

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

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

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

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

    【讨论】:

    • 您介意分享您的测试程序吗? - 您如何以这样的粒度确定堆使用情况?
    • 我没有手边的代码,但是在 StringBuilder 初始容量中每增加 4 个单位,堆使用量就会增加一个步骤,然后对于接下来的 3 个大小大致相同,然后在下一个倍数跳跃之前4 再次。 但是 那是 4 个字符,意思是 8 个字节,对吧?感谢您的询问,我明天一定会再次测试以验证这一点。
    • 所以您观察到堆使用量以 1000000 x 4 字节的步长增加? ——我不敢估计一个[数据结构]将占用多少字节的Java堆空间,而不是char,也不是任何Java程序中的任何其他值/类型。 - 此外,无论堆的分配粒度如何,GC 决定将内存释放回堆的粒度是未知的,并且会影响任何测量。 - 如果您出于好奇和/或测量给定 JVM 的某些特性而进行测试,请继续。 - 否则,......见我上面的回答:)
    • 我观察到 1000000 x new StringBuilder(112) 占用的堆数量与 1000000 x new StringBuilder(115) 大致相同。将容量增加到 116 会显着增加堆使用量,120 会再次增加它等等。我很惊讶地认为它是 4 个字节,但是 4 个字符 = 8 个字节更有意义(在 64 位 JVM 上)。
    猜你喜欢
    • 1970-01-01
    • 2012-03-10
    • 1970-01-01
    • 2011-02-01
    • 2010-12-29
    • 1970-01-01
    • 2020-05-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多