重用StringBuffer

时间:2012-04-16 08:59:04

标签: java performance jdk1.6 jdk1.5 stringbuffer

我知道concat,StringBuffer和StringBuilder之间的区别。我知道StringBuffer.toString支持数组的内存问题可能会爆炸内存。我甚至意识到JDK Sun优化包括为初始容量分配2的幂。

但我仍然想知道重用StringBuffer(在toString()中使用)的最佳方法,或者,如果重用StringBuffer是相关的。考虑到内存和速度性能哪一个更好?

public String toString2() {
  StringBuffer sb = new StringBuffer(<size>) 
  ... several .append(stuff) ...
  sb.trimToSize()
  return sb.toString()
}

private StringBuffer sb = new StringBuffer(<size>) 
public String toString2() {
  sb.delete()
  sb.setLength(1024)
  sb.trimToSize() 
  ... several .append(stuff) ...
  return sb.toString()
}

为什么?

4 个答案:

答案 0 :(得分:3)

我想说第一个例子肯定更清晰,更容易阅读和更安全 - 这应该几乎总是胜过性能微优化问题。 如果确实存在性能问题,您可以(通过具体测量)证明它是由这段代码引起的还可以通过测量证明,在您的本地环境中,第二个示例明显更快,然后 - 而只有 - 您有正当理由使用它。

否则,您的问题没有一般性答案。如果人们声称第二个例子的平均值 n %更快,如果它在你的机器上没有任何差别(因为环境不同,或者因为实际情况),它会对你有什么帮助?你的应用程序中很少调用这段代码吗?

然而,我个人的直觉是,在现代JVM上(阅读:至少在JDK6上,但可能已经在JDK5上),第一个例子可能实际上更快,因为聪明的GC技巧使得分配/释放短 - 生活对象非常便宜。特别是如果您使用StringBuilder而不是StringBuffer,它没有同步开销。

答案 1 :(得分:2)

  1. 使用StringBuilderStringBuffer的非同步变体 - 可以直接提供性能提升。
  2. 无需致电trimToSize - 您只是强迫StringBuilder制作新的字符数组。
  3. 由于JVM针对短期对象的分配进行了高度优化,因此您可以通过重用StringBuilder来节省非常少的资金。
  4. 仅当您无法在单个表达式中表达字符串时,才使用StringBuilder而不是简单的连接表达式 - 例如,您正在迭代某些内容。连接使用StringBuilder编译基本相同的代码。

答案 2 :(得分:0)

如果性能受到关注,我不会在所有esp中使用StringBuffer。

如果你不能确定只有一个线程会调用toString(),我每次都会创建一个StringBuilder。

你遇到的另一个问题是不同的数据类型可能会产生大量垃圾,例如: intdouble这可以减少您可能获得的任何好处。

我不会回收StringBuilder,我会保持简单。如果你真的需要最大的性能,我会使用一个不同的解决方案,比如直接的ByteBuffer和一个不会产生垃圾的库。

答案 3 :(得分:0)

尝试两种性能测试。与所有性能问题一样,它取决于上下文以及如何调用方法。

几点说明:

  • StringBuilder不是线程安全的,但在第一个示例中,线程安全不是问题,因为您的方法不使用字段。这使StringBuilderStringBuffer更快。
  • 你的第二种方法不是线程安全的,所以如果你有多个线程调用该方法,那么两个线程都将使用safe StringBuffer,所以你最终会得到一个包含两个调用元素的字符串
  • 如果你保持StringBuffer(第二个例子),取决于你使用该方法的频率,你实际上可能会保留更多的内存,因为垃圾收集器不会收集{{{}使用的内存1}},可供其他对象使用。