为什么在循环期间追加TextBox.Text会在每次迭代时占用更多内存?

Rac*_*hel 82 c# wpf

简短的问题

我有一个运行180,000次的循环.在每次迭代结束时,它应该将结果附加到TextBox,TextBox是实时更新的.

使用MyTextBox.Text += someValue导致应用程序占用大量内存,并且在几千条记录之后它耗尽了可用内存.

是否有更有效的方式将文本附加到TextBox.Text180,000次?

编辑我真的不关心这个特定情况的结果,但我想知道为什么这似乎是一个记忆猪,并且如果有一种更有效的方法将文本附加到TextBox.


长(原始)问题

我有一个小应用程序,它读取CSV文件中的ID号列表,并为每个应用程序生成PDF报告.生成每个pdf文件后,ResultsTextBox.Text将附加到已处理的报告的ID号以及已成功处理的报告的ID号.该进程在后台线程上运行,因此ResultsTextBox会在项处理时实时更新

我目前正在针对180,000个ID号运行该应用程序,但是应用程序占用的内存随着时间的推移呈指数级增长.它从大约90K开始,但是大约3000条记录占用大约250MB,而4000条记录占用大约500 MB的内存.

如果我注释掉结果文本框的更新,内存保持相对静止大约90K,所以我可以假设写作ResultsText.Text += someValue是导致它吃内存的原因.

我的问题是,这是为什么?将数据附加到不吃内存的TextBox.Text的更好方法是什么?

我的代码看起来像这样:

try
{
    report.SetParameterValue("Id", id);

    report.ExportToDisk(ExportFormatType.PortableDocFormat,
        string.Format(@"{0}\{1}.pdf", new object[] { outputLocation, id}));

    // ResultsText.Text += string.Format("Exported {0}\r\n", id);
}
catch (Exception ex)
{
    ErrorsText.Text += string.Format("Failed to export {0}: {1}\r\n", 
        new object[] { id, ex.Message });
}
Run Code Online (Sandbox Code Playgroud)

还应该值得一提的是,该应用程序是一次性的事情,并不需要花费几个小时(或几天:)来生成所有报告.我主要担心的是,如果它达到系统内存限制,它将停止运行.

我没关系更新结果TextBox注释掉来运行这个东西,但我想知道是否有一种更有效的内存方式将数据附加到TextBox.Text未来的项目中.

key*_*rdP 119

我怀疑内存使用量如此之大的原因是因为文本框保持堆栈以便用户可以撤消/重做文本.在您的情况下似乎不需要该功能,因此请尝试设置IsUndoEnabled为false.

  • 大多数情况下,用户和开发人员都希望文本框的功能类似于标准文本框(即能够撤消/重做).在诸如OP的要求等边缘情况下,它可以证明是一种阻碍.如果大多数人使用它,那么它应该是默认的.为什么您希望边缘情况强制标准功能成为选择加入? (33认同)

Cyp*_*100 14

TextBox.AppendText(someValue)而不是TextBox.Text += someValue.它很容易被遗漏,因为它在TextBox上,而不是TextBox.Text.与StringBuilder一样,这将避免在每次添加内容时创建整个文本的副本.

看看这与IsUndoEnabled来自keyboardP的答案的旗帜相比,会很有趣.


Dar*_*g8r 9

不要直接附加到text属性.使用StringBuilder进行追加,然后在完成后,将.text设置为stringbuilder中的完成字符串

  • 我忘了在后台线程上提到循环运行,结果实时更新 (2认同)

Cha*_*ion 5

我没有使用文本框,而是执行以下操作:

  1. 打开文本文件并将错误流式传输到日志文件以防万一.
  2. 使用列表框控件来表示错误,以避免复制潜在的大量字符串.