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
这些测试数据来自下面的测试程序.可以看出,无论有多少次执行Append()和Clear(),容量都不会改变.但是在使用Insert()和Clear()时它确实在不断增长.
问题:使用Insert()和Clear()时StringBuilder是否存在内存泄漏是否正确,因为容量不断增长,最终会导致Out of Memory异常?
要自己测试它,只需增加outerIndex的上限即可获得异常.
如果这确实应该被视为内存泄漏,我该如何向Microsoft报告?
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:
经过一些搜索,我发现在Clear()之后将Capacity设置为0的建议,如下所示:
stringBuilder.Clear(); stringBuilder.Capacity = 0;
这可以防止内存泄漏,并在重复使用Insert()时导致Out of Memory异常,但它也无法重用StringBuilder,这是为了防止内存的分配和释放以实现更高的速度.而不是设置Capacity = 0,也可以使用新的StringBuilder而不是Clear().
似乎Insert()没有重用已经分配给StringBuilder的未使用的内存,但是不管添加Clear(),都会不断添加新的内存.我仍然觉得这是一个错误,因为尽管清除了StringBuilder,谁会期望内存耗尽?如果这是一个错误并且应该向Microsoft报告,我将不胜感激.
EDIT2:
我向微软报告了这个错误:
https://connect.microsoft.com/VisualStudio/feedback/details/1242873
结束语:
>从之前的帖子中我发现了一个经验,评论者很快就说我的程序存在问题.他们非常粗鲁地评论,即使是他们错了.
>从之前的帖子中我发现,评论者喜欢将问题标记为“此问题已经有答案”,这只是因为他们不理解我的问题与其他问题之间的区别.实际上,对于StringBuilder和Out of Memory,stackoverlow上有许多已回答的问题.我阅读了google或stackoverlow所能找到的所有内容.它们是关于APPEND()和关于非常长的文本.它们与Insert()无关.请注意,即使使用非常短的字符串并且仅在使用Insert()时出现问题,但在使用Append()时却不会出现问题!
>从之前的帖子中我发现了评论者喜欢建议使用不同编程的经验,例如避免使用Insert()并通过使用Append并以反向顺序添加行来解决问题.虽然在某些情况下这可能是可能的,但我觉得Insert()和Clear()应该正常工作,我们应该让Microsoft知道是否存在问题.
解决方法
Clear()
该文件指出:
Removes all characters from the current StringBuilder instance.[…]
Calling the Clear method does not modify the current instance’s Capacity or MaxCapacity property.07000
Insert()
在这里,文档指出先前的内容已经转移,并且根据需要调整容量. (doc)这不完全清楚,但我假设分配了新的内存容量新长度,其余的被复制.现在.这可能不是最佳解决方案,但我认为这是它的实现方式.因此,可以预期内存不足的情况.
另一个建议:始终插入第一个位置 – 无论实施 – 都非常昂贵.如果只需要一次考虑结果,请考虑使用List< string>在第0位插入新行,然后在列表上迭代一次并构建字符串.
编辑:
在查看(假设)source之后,我认为StringBuilder确实为每个插入分配了一个新实例作为’chunk’ – 无论其他任何romm可用.我跟着调用了MakeRoom,在第2044行分配了一个新的块.