我需要向StringBuilder添加一些行,其中最后添加的行应该在字符串的开头,而最老的行应该在末尾。我增加了一个新的行如下:
stringBuilder.Insert(0, "Some text." + Environment.NewLine);一旦完成,我就像这样清空StringBuilder:
stringBuilder.Clear();我多次重复使用相同的StringBuilder,这会导致内存不足的异常。
我研究了下面的测试程序的问题,这表明在使用Append()和Clear()时,无论使用多少次,StringBuilder的容量都保持不变。但是当使用Insert()和Clear()时,StringBuilder的容量不断增加。以下是测试结果:
stringbuilder.Capacity
Iteration Append Insert
0: 81984, 78016
1: 81984, 155938
2: 81984, 233860
3: 81984, 311782
4: 81984, 389704
5: 81984, 467626
6: 81984, 545548
7: 81984, 623470
8: 81984, 701392这些测试数据来自下面的测试程序。正如我们所看到的那样,无论你做了多少次追加()和清除(),容量都不会改变。但在使用Insert()和Clear()时,它确实会不断增长。
问题:在使用Insert()和Clear()时说StringBuilder内存泄漏是正确的,因为容量不断增长,这最终导致内存不足的异常?
要自己测试它,只需增加outerIndex的上限以获得异常。
如果这确实应该被认为是内存泄漏,我如何向微软报告呢?
using System;
using System.Text;
namespace TestStringBuilder {
class Program {
static void Main(string[] args) {
StringBuilder stringBuilderAppend = new StringBuilder();
StringBuilder stringBuilderInsert = new StringBuilder();
string capacityGrow = "";
for (int outerIndex = 0; outerIndex < 9; outerIndex++) {
for (int innerIndex = 0; innerIndex < 1000; innerIndex++) {
stringBuilderAppend.Append("Just some text to fill stringbuffer with 01234567890qwertyuiopasdfghjklzxcvbnm");
stringBuilderInsert.Insert(0, "Just some text to fill stringbuffer with 01234567890qwertyuiopasdfghjklzxcvbnm");
}
stringBuilderAppend.Clear();
stringBuilderInsert.Clear();
capacityGrow += outerIndex + ": " + stringBuilderAppend.Capacity + ", " + stringBuilderInsert.Capacity + Environment.NewLine;
}
//check in the debugger capacityGrow to see the capacity used in each iteration
System.Diagnostics.Debugger.Break();
}
}
}Edit1:在进一步搜索之后,我发现在清除()之后将容量设置为0的建议,如下所示:
stringBuilder.Clear();
stringBuilder.Capacity = 0;这防止了重复使用Insert()时内存泄漏和内存异常的产生,但它也违背了重用StringBuilder的目的,即防止内存的分配和取消分配以获得更高的速度。相反,要设置Capacity=0,最好使用一个新的StringBuilder,而不是Clear()。
看来Insert()并没有重用已经分配给StringBuilder的未使用内存,而是继续添加新内存,尽管使用了Clear()。我仍然觉得这是一个bug,因为谁会期望在清除StringBuilder的情况下耗尽内存?如果这是一个bug,如果它应该报告给微软,我会很感激你的评论。
Edit2: --我向微软报告了这个bug:https://connect.microsoft.com/VisualStudio/feedback/details/1242873
请按照这个链接并更新错误,否则我担心微软不会调查它:
闭幕词:
发布于 2015-04-11 05:50:44
我想说的是,这种行为是预料之中的:
Clear()医生说:
从当前StringBuilder实例中移除所有字符.调用Clear方法不会修改当前实例的容量或MaxCapacity属性.见文献资料
因此,Clear()删除了内容,但保留了分配的内存。
Insert()在这里,doc声明以前的内容被转移,容量根据需要进行调整。(文档这一点还不完全清楚,但我假设分配了新的内存容量+新长度,并复制了其他内存容量。现在。这可能不是最佳解决方案,但我认为这就是实现它的方式。所以记忆不足的情况是意料之中的。
另一个建议是:无论实现如何,总是在第一个位置插入是相当昂贵的。如果只需要结果一次,可以考虑使用List<string>,在0位置插入新行,然后迭代列表一次,然后构建字符串。
编辑:
在查看了(假设的) 来源之后,我认为StringBuilder确实为每一个插入分配了一个新的实例,作为‘块’--不管其他任何可用的romm。我跟踪调用到MakeRoom,在第2044行分配一个新块。
发布于 2015-08-11 23:42:40
我们遇到了同样的问题
Replace()当我们将我们的网络应用程序从.net 2升级到.net 4时。
显然,StringBuilder的实现发生了变化。请参阅StringBuilder类是如何实现的?每次追加时,它是否在内部创建新的字符串对象?
我们所研究的解决办法:
https://stackoverflow.com/questions/29574469
复制相似问题