【问题标题】:What is the optimal StringBuffer initial capacity for inputs with drastically varying lengths?对于长度变化很大的输入,最佳 StringBuffer 初始容量是多少?
【发布时间】:2012-01-21 13:38:59
【问题描述】:

大家下午好,我正在使用java.lang.StringBuilder 来存储一些字符。我不知道我要提前存储多少个字符,除了:

  1. 60% 的情况下,只有(完全)7 个字符
  2. 39% 的时间,它(大约)是 3500 个字符
  3. 1% 的时间,大约是 20k 个字符

我们如何计算应该使用的最佳初始缓冲区长度?

目前我正在使用new java.lang.StringBuilder(4000),但这只是因为我之前懒得想。

【问题讨论】:

  • 听起来默认值在大多数情况下可能是最佳的。你能回收你的 StringBuilders 吗?
  • “我们应该忘记小的效率,比如说大约 97% 的时间:过早的优化是万恶之源”
  • @PeterLawrey 不,它们不可回收(我的意思是它们可以,而且我相信这会更加优化,但需要更改源代码)。
  • @natix 对过早优化的恐惧是我插入 4000 并首先完成它的部分原因。不过既然是post-mature,简单地改变构造函数的参数也不是太难吧?
  • 任何更改都需要更改源代码。您可以在没有对象池样式回收的情况下使对象可重用。

标签: java math language-agnostic buffer stringbuilder


【解决方案1】:

这里有两个因素:时间和内存消耗。时间主要受调用java.lang.AbstractStringBuilder.expandCapacity() 的次数影响。当然,每次调用的成本与缓冲区的当前大小成线性关系,但我在这里简化并仅计算它们:

expandCapacity()的数量(时间)

默认配置(16 个字符容量)

  • 在 60% 的情况下,StringBuilder 将扩展 0 倍
  • 在 39% 的情况下,StringBuilder 将扩展 8 倍
  • 在 1% 的情况下,StringBuilder 将扩展 11 倍

expandCapacity 的预期数量是 3,23。

初始容量 4096 个字符

  • 在 99% 的情况下,StringBuilder 将扩展 0 倍
  • 在 1% 的情况下,StringBuilder 将扩展 3 倍

expandCapacity 的预期数量是 0,03。

如您所见,第二种情况似乎要快得多,因为它很少需要扩展 StringBuilder(每 100 个输入三次)。但是请注意,第一次扩展不太重要(复制少量内存);此外,如果您以大块的形式向构建器添加字符串,它会在更少的迭代中更积极地扩展。

另一方面,内存消耗增加:

内存消耗

默认配置(16 个字符容量)

  • 在 60% 的情况下,StringBuilder 将占用 16 个字符
  • 在 39% 的情况下,StringBuilder 将占用 4K 个字符
  • 在 1% 的情况下,StringBuilder 将占用 32K 个字符

预期的平均内存消耗为:1935 个字符。

初始容量 4096 个字符

  • 在 99% 的情况下,StringBuilder 将占用 4K 个字符
  • 在 1% 的情况下,StringBuilder 将占用 32K 个字符

预期的平均内存消耗为:4383 个字符。


TL;DR

这让我相信,将初始缓冲区扩大到 4K 会使内存消耗增加两倍以上,同时将程序速度提高两个数量级

底线是:试试吧!编写一个基准来处理具有不同初始容量的不同长度的数百万个字符串并不难。但我相信更大的缓冲区可能是一个不错的选择。

【讨论】:

    猜你喜欢
    • 2011-12-22
    • 2014-07-22
    • 2010-12-10
    • 2011-09-22
    • 2012-10-22
    • 2012-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多