WPF RichTextBox内存泄漏问题

6

在我的应用程序中,我有许多动态创建的RichTextBoxes。我发现这个应用程序存在内存泄漏问题,这是由RichTextBox控件引起的。为了证明内存泄漏是由控件引起的,我编写了以下测试方法:

for (int i = 0; i < 3000; i++)
        {
            Control rich = new RichTextBox();
            pnl.Content = rich;
        }
GC.Collect();
GC.WaitForPendingFinalizers();

pnl是在Xaml代码中声明的ContentControl。
如果运行以下代码,您会发现内存使用量正在迅速增长。

有什么解决问题的想法吗? 我考虑过创建一个对象池,但这会使我的应用程序变得复杂,我宁愿避免这种情况。


编辑:我已经添加了垃圾回收器的调用以证明对象没有被垃圾回收 - 使用和不使用GC collect方法时内存使用量没有改善。 请注意,在循环内调用rich.Dispose可以消除内存使用量的增长。


你如何衡量内存? - H H
您可以在Windows任务管理器中看到内存使用量增加。 - Elad
你描述了一个完全不同的情况。你没有给垃圾回收器收集的机会。我只运行了不到一分钟的应用程序,并强制进行了垃圾回收。 - Elad
@Michael - 我尝试在循环中使用TextBox来运行代码(没有GC收集)。我无法复现TextBox的内存泄漏问题。 - Elad
@Elad:好的,知道了,我想我可以。 - Michael Petrotta
显示剩余2条评论
5个回答

8

这并不意味着你的应用程序存在内存泄漏,而是表明你的应用程序正在使用大量内存。只有在RichTextBox控件超出作用域后没有被释放(检测托管对象的内存泄漏非常困难且无法证明)时才算是泄漏。

一个普遍的误解是,对象超出作用域将导致它被垃圾回收。这只是使它有资格被回收。该对象可能从理论上讲永远不会被回收直到应用程序终止。它与其他控件不同,增长速度与RichTextBox相关,并不意味着RichTextBox存在内存泄漏,只是表明每个实例使用的内存比其他控件多。虽然这些信息可能很有用,但在确定是否存在内存泄漏时并没有帮助。


你尝试过运行测试代码吗?内存使用量会迅速增长到整个计算机变得缓慢的地步。你可以随便使用任何WPF控件来尝试这段代码,你会发现没有显著的内存增长。请注意,当被新控件替换时,控件会失去其作用域。 - Elad
强制进行垃圾回收并不会改变内存使用情况(请参见我的编辑)。 - Elad

3

在其他地方找到了这篇文章,根据我的测试结果看起来是正确的。

当创建一个FlowDocument时,相对昂贵的格式化上下文对象也会在其StructuralCache中被创建。当你在一个紧密循环中创建多个FlowDocs时,为每个FlowDoc创建一个StructuralCache。在循环结束时调用Gc.Collect,希望回收一些内存。StructuralCache有一个终结器释放这个格式化上下文,但不是立即释放。终结器有效地安排了一个操作,在DispatcherPriority.Background下释放上下文。

因此,RichTextBox(或FlowDocument)并非泄漏,只是在等待后台线程清理。它运行的时间谁都不知道。我希望它实现了一个dispose方法,可以立即强制清理。


1
原始帖子:http://social.msdn.microsoft.com/forums/en-US/wpf/thread/9cba6b80-c402-4f89-b300-6a9f8e4d7e37/ - Elad

1

我们在winforms 2.0中遇到了同样的问题,不得不购买第三方富文本控件。我猜微软没有费心去修复它...


2
我非常确定Winforms和WPF版本的RichTextBox之间没有实现上的相似之处。 - ArielBH

1

0
关于您的编辑:
您在循环结束后添加了GC调用,并且已经创建了所有3000个RichTextBox。
虽然我同意,当它被新的替换时,先前的RichTextBox没有在循环内释放似乎很奇怪,但是这是一个非常紧密的循环,GC可能没有机会在循环终止之前“做它的事情”。
我认为这不是一个好主意(但在测试代码中应该没问题),但您是否尝试将GC调用移动到循环内部?

我尝试了你的建议,但似乎没有任何效果。 - Elad
@Elad - 哦,好吧。它似乎是一个合理的建议。 - ChrisF

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接