Question

In my application, I have a lot of RichTextBoxes that are created dynamically in run time. I realized that the application has a memory leak, which is caused by the RichTextBox controls. To prove that the memory leaks because of the control I wrote the following test method:

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

pnl is a ContentControl that is declared in Xaml code.
If you run the following code, you can see that the memory usage is growing rapidly.

Any ideas how to solve the problem? I considered creating an object pool, but this would complicate my application, and I rather avoid it.


edit: I've added call to the garbage collector to demonstrate that the objects are not garbage collected - there is no improvement in the memory usage with and without the call to the GC collect method. Note that calling rich.Dispose within the loop eliminates the memory usage growth.

Was it helpful?

Solution

Found this elsewhere, and it seems to be correct as far as my testing is concerned.

When a FlowDocument is created, relatively expensive formatting context objects are also created for it in its StructuralCache. When you create multiple FlowDocs in a tight loop, a StructuralCache is created for each FlowDoc. Let's you called Gc.Collect at the end of the loop, hoping to recover some memory. StructuralCache has a finalizer releases this formatting context, but not immediately. The finalizer effectively schedules an operation to release contexts at DispatcherPriority.Background.

So the RichTextBox (or FlowDocument) in case is not leaking just waiting on a background thread to cleanup. When it runs exactly who knows. I wish this just implemented a dispose method that would force a cleanup immediately.

OTHER TIPS

This isn't an indication that your application has a memory leak, it's an indication that your application is using a lot of memory. It's a leak if the RichTextBox controls don't get released at some point after they've fallen out of scope (detecting memory leaks on managed objects is notoriously difficult and unprovable).

A common misconception that an object falling out of scope will cause it to be garbage collected. This just makes it eligible to be collected. The object may theoretically never be collected until the application terminates. The fact that it grows with RichTextBox and not with other controls is not an indication that there is a memory leak in the RichTextBox, it's just an indication that it uses more memory per instance than other controls. While this information may be useful, it doesn't help when determining whether or not there's a memory leak.

We had the same problem in winforms 2.0 and we had to buy a 3rd party rich text control. I guess that Microsoft didn't bother to fix it...

This fixed the issue to me: http://blingcode.blogspot.com/2010/10/memory-leak-with-wpfs-richtextbox.html

Basically add two attributes to each RichTextBox :) :) IsUndoEnabled="False"

Regarding your edit:

You've added the GC calls after the loop terminates and all 3000 RichTextBoxes have been created.

While I agree that it seems odd that the previous one isn't freed inside the loop when it's replaced by a new one, it's such a tight loop that the GC probably isn't getting a chance to "do it's stuff" before the loop terminates.

I don't think it's a good idea (but it should be OK in test code), but have you tried moving the GC calls inside the loop?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top