StringBuilder – 重置或创建新的

我有一个条件,StringBuilder保持存储与大平面文件(100的MB)模式匹配的行。 但是在达到条件后,我将StringBuilder varialble的内容写入文本文件。

现在我想知道是否应该通过重置对象来使用相同的变量 – >

stringBuilder.delete(0,stringBuilder.length()) 

要么

 stringBuilder=new StringBuilder(); 

请建议您考虑性能和OOM问题哪个更好。

我认为StringBuilder#delete(start, end)仍然是昂贵的调用,你应该这样做:

 stringBuilder.setLength(0); 

重置它。


更新:查看StringBuilder源代码之后看起来setLength(int)保留旧缓冲区完好无损,最好在上面的调用之后调用: StringBuilder#trimToSize() ,它会attempts to reduce storage used for the character sequence

所以这样的事情会更有效率:

 stringBuilder.setLength(0); // set length of buffer to 0 stringBuilder.trimToSize(); // trim the underlying buffer 

Imho,我建议使用新的:

 stringBuilder = new StringBuilder(); 

我从来没有听说过StringBuilder中的内存泄漏,但是当你真正推动你永远不知道的限制时。 我每次都会使用一个新实例来对冲我的赌注。

在最坏的情况下,你可能会失去一些效率,而gc会得到锻炼,但你排除了OOM的可能性。

因此,为了清楚起见,我个人会采用新的方法。

一个根本区别是sb.delete保留引用,而构造函数丢失它。

如果您的SB是方法参数,并且应该用于将内容传递回调用者,则必须使用sb.delete。 来电者持有原始参考。

那么两者之间有更大的差异。 第一个保留了删除字符之前的容量(即stringBuilder.capacity() ),而第二个创建了一个具有默认容量16的新StringBuilder 。当然,你可以将stringBuilder.capacity()作为参数传递给构造函数,但重要的是要理解这里的区别。

在任何情况下,我都非常怀疑您会发现这两种变体之间存在显着的性能差异,因此请选择更易读且更易于管理的变量。 只有当您最终确定这会导致某种瓶颈时,才应该改变方法。

我会用:

  stringBuilder = new StringBuilder(); 

因为如果你用大量数据填充它,请调用stringBuilder.setLength(0); 不会取消分配支持数组,因此您可以看到内存使用率不必要地保持高水平。

此外,它更容易阅读和理解。

理想情况下我们应该使用new StringBuilder()从grepcode中挖掘StringBuilder类中的一点我会了解以下内容。

创建新对象:

 /** * Creates an AbstractStringBuilder of the specified capacity. */ AbstractStringBuilder(int capacity) { value = new char[capacity]; } 

new StringBuilder()创建一个具有初始容量char数组的新对象。 这里的开销:将调用GC来清除旧对象。

使用删除:

 public AbstractStringBuilder delete(int start, int end) { if (start < 0) throw new StringIndexOutOfBoundsException(start); if (end > count) end = count; if (start > end) throw new StringIndexOutOfBoundsException(); int len = end - start; if (len > 0) { System.arraycopy(value, start+len, value, start, count-end); count -= len; } return this; } 

使用Length和TrimToSize:

 public void trimToSize() { if (count < value.length) { value = Arrays.copyOf(value, count); } } 

将调用copyOf从数组类

public static char [] copyOf(char [] original,int newLength){char [] copy = new char [newLength]; System.arraycopy(original,0,copy,0,Math.min(original.length,newLength)); 返回副本; }

现在它还将调用System.arrayCopy ,这是一个本机方法。 现在,如果你在copyOf中看到我们再次创建一个长度为0的新charArray,当我们尝试再次向其添加数据时,它将调用expand,因为当前长度为0 。 所以我认为最好调用新的StringBuilder()

你可以在grepcode上看到上面的代码

PS:@ user3241961是写的,以防您使用此对象的引用,然后new将需要再次设置它

总是可以比重新分配新对象更便宜地重用创建的对象。 它还避免了垃圾收集器的额外工作,因为您只处理一个对象。

更快的方法是:

 stringBuilder.setLength(0); 

如果您处于紧密循环中并且在将数据写入文件后将继续返回该循环,则应该重新使用StringBuilder。 没有理由不这样做,而且比搅拌GC更好。 如果您使用C或C ++编写,则可以重用缓冲区。

此外,虽然delete(…)方法调用System.arraycopy,但复制的字节数为0,因此它无关紧要。

啊 – 有人提到我有一个setLength(…)方法,它是重用缓冲区的最快方法。