Java StringBuilder-重置或创建新的
我有一个条件,StringBuilder不断存储与大型平面文件(100 MB)中的模式匹配的行。但是,在达到某个条件后,我将StringBuilder变量的内容写入文本文件 现在我想知道是否应该通过重置对象来使用相同的变量->Java StringBuilder-重置或创建新的,java,stringbuilder,Java,Stringbuilder,我有一个条件,StringBuilder不断存储与大型平面文件(100 MB)中的模式匹配的行。但是,在达到某个条件后,我将StringBuilder变量的内容写入文本文件 现在我想知道是否应该通过重置对象来使用相同的变量-> stringBuilder.delete(0,stringBuilder.length()) 或 就性能和OOM问题而言,请建议您认为哪一个更好。我认为StringBuilder#delete(start,end)仍然很昂贵,您应该: stringBuilder.set
stringBuilder.delete(0,stringBuilder.length())
或
就性能和OOM问题而言,请建议您认为哪一个更好。我认为
StringBuilder#delete(start,end)
仍然很昂贵,您应该:
stringBuilder.setLength(0);
重新设置它
更新:查看后,似乎
setLength(int)
保留了旧的缓冲区,最好在上述调用之后调用:StringBuilder#trimToSize()
,尝试减少用于字符序列的存储空间
所以像这样的事情会更有效率:
stringBuilder.setLength(0); // set length of buffer to 0
stringBuilder.trimToSize(); // trim the underlying buffer
这两者之间有更大的区别。第一个将保留删除字符之前的所有容量(即stringBuilder.capacity()
),而第二个将使用默认容量创建新的stringBuilder
。当然,您可以将stringBuilder.capacity()
作为参数传递给构造函数,但是理解这里的区别很重要
在任何情况下,我都非常怀疑您是否会看到这两个变体之间存在实质性的性能差异,因此请选择可读性更好、更易于管理的变体。只有当您最终确定这会造成某种瓶颈时,才应该改变您的方法。Imho,我建议您使用新的:
stringBuilder = new StringBuilder();
我从来没有听说过StringBuilder中存在内存泄漏,但当您真正达到极限时,您永远不会知道。我会通过每次使用一个新实例来对冲我的赌注
在最坏的情况下,你可能会失去一些效率,gc得到锻炼,但你排除了OOM的可能性
正因为如此,而且出于明确的原因,我个人会采用新方法。我会使用:
stringBuilder = new StringBuilder();
因为如果用大量数据填充,调用stringBuilder.setLength(0)
不会取消分配备份阵列,因此您可能会看到内存使用率不必要地保持高水平
此外,它更易于阅读和理解。如果您处于一个紧密的循环中,并且在将数据写入文件后将继续回到该循环中,您肯定应该重新使用StringBuilder。没有理由不这样做,这比搅动GC要好。如果你用C或C++写这个,你会重新使用缓冲区。
此外,虽然delete(…)方法调用System.arraycopy是真的,但复制的字节数是0,因此不重要
啊-有人提到我有一个setLength(…)方法,它是重新使用缓冲区的最快方法。一个基本区别是sb.delete保留引用,而构造函数丢失它
如果SB是一个方法参数,并且应该用于将内容传递回调用方,则必须使用SB.delete。调用者持有原始引用。理想情况下,我们应该使用新的StringBuilder()
从StringBuilder类中挖掘一点,我了解了以下内容
创建新对象:
/**
* Creates an AbstractStringBuilder of the specified capacity.
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
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;
}
public void trimToSize() {
if (count < value.length) {
value = Arrays.copyOf(value, count);
}
}
new StringBuilder()创建具有初始容量字符数组的新对象。
此处的开销:将调用GC以清除旧对象
使用删除:
/**
* Creates an AbstractStringBuilder of the specified capacity.
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
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;
}
public void trimToSize() {
if (count < value.length) {
value = Arrays.copyOf(value, count);
}
}
public AbstractStringBuilder删除(int开始,int结束){
如果(开始<0)
抛出新StringIndexOutOfBoundsException(开始);
如果(结束>计数)
结束=计数;
如果(开始>结束)
抛出新的StringIndexOutOfBoundsException();
int len=结束-开始;
如果(len>0){
System.arraycopy(值,开始+长度,值,开始,计数结束);
计数-=len;
}
归还这个;
}
使用长度和修剪大小:
/**
* Creates an AbstractStringBuilder of the specified capacity.
*/
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}
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;
}
public void trimToSize() {
if (count < value.length) {
value = Arrays.copyOf(value, count);
}
}
public void trimToSize(){
如果(计数<值.长度){
value=Arrays.copyOf(值,计数);
}
}
将从数组类调用copyOf
public static char[]copyOf(char[]original,int newLength){
char[]copy=new char[newLength];
系统阵列副本(原件、0、副本、0、,
Math.min(original.length,newLength));
返回副本;
}
现在它还将调用System.arrayCopy,这是一种本机方法。
现在,如果您看到在copyOf中,我们再次创建了一个长度为0的新字符,
当我们尝试再次向其添加数据时,它将调用expand,因为当前长度将为0。
因此,我认为最好调用新的StringBuilder()
您可以在上看到上面的代码
PS:@user3241961是write,如果您正在使用此对象的引用,则new需要重新设置它重用创建的对象比始终分配新对象更便宜。它还避免了垃圾收集器的额外工作,因为您只处理一个对象
更快的方法是:
stringBuilder.setLength(0);
作为参考,delete()
call执行一个系统。arraycopy
。您应该根据您的应用程序工作流进行基准测试,并选择最适合您的应用程序。@SotiriosDelimanolis但在本例中,arraycopy的长度为0。我将分析这两个选项,以测量内存和cpu使用情况的性能,并获得特定应用程序的最终答案案例不过,在我看来,最好的选择是stringBuilder=newstringbuilder()
并让GC完成它的工作。使用此技术可能会泄漏内存。如果创建越来越大的字符串,然后再创建越来越小的字符串,那么即使没有全部使用,底层的char[]
也会越来越大。@anubhava我不是说性能。setLength()
方法