微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

.net – 使用Insert()和Clear()时StringBuilder中的内存泄漏

我需要在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

这些测试数据来自下面的测试程序.可以看出,无论有多少次执行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

所以Clear()删除内容但保留内存分配.

Insert()

在这里,文档指出先前的内容已经转移,并且根据需要调整容量. (doc)这不完全清楚,但我假设分配了新的内存容量新长度,其余的被复制.现在.这可能不是最佳解决方案,但我认为这是它的实现方式.因此,可以预期内存不足的情况.

一个建议:始终插入第一个位置 – 无论实施 – 都非常昂贵.如果只需要一次考虑结果,请考虑使用List< string>在第0位插入新行,然后在列表上迭代一次并构建字符串.

编辑:

在查看(假设)source之后,我认为StringBuilder确实为每个插入分配了一个新实例作为’chunk’ – 无论其他任何romm可用.我跟着调用了MakeRoom,在第2044行分配了一个新的块.

原文地址:https://www.jb51.cc/mssql/84011.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐