[Updated, see bottom!]
There is a memory leak in our WinForms application hosting a WPF FlowDocumentReader in an ElementHost. I have recreated this issue in a simple project and added the code below. 
What the application does
When I press button1:
- A 
UserControl1which just contains aFlowDocumentReaderis created and set to be theElementHost'sChild - A 
FlowDocumentis created from a text file (it just contains aFlowDocumentwith aStackPanelwith a few thousand lines of<TextBox/>) - The 
FlowDocumentReader'sDocumentproperty is set to thisFlowDocument 
At this point, the page renders the FlowDocument correctly. A lot of memory is used, as expected.
The problem
If
button1is clicked again, memory usage increases, and keeps increasing every time the process repeats! The GC isn't collecting despite loads of new memory being used! There are no references which shouldn't be there, because:If I press
button2which setselementHost1.Childto null and invokes the GC (see the code below), another weird thing happens - it will not clean up the memory, but if I keep clicking it for a few seconds, it will eventually free it!
It is unacceptable for us that all this memory stays used. Also, removing the ElementHost from the Controls collection, Disposing it, setting the reference to null, and then invoking the GC does not free up the memory.
What I want
- if 
button1is clicked mutiple times, memory usage shouldn't keep going up - I should be able to free all the memory (this is just one window in the "real" application, and I want to do this when it is closed)
 
This is not something where the memory usage doesn't matter and I can just let the GC collect it whenever. It actually ends up noticeably slowing down the machine.
The code
If you would rather just download the VS project, I've uploaded it here: http://speedy.sh/8T5P2/WindowsFormsApplication7.zip
Otherwise, here is the relevant code. Just add 2 buttons to the form in the designer and hook them up to the events. Form1.cs:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows.Documents;
using System.IO;
using System.Xml;
using System.Windows.Markup;
using System.Windows.Forms.Integration;
namespace WindowsFormsApplication7
{
    public partial class Form1 : Form
    {
        private ElementHost elementHost;
        public Form1()
        {
            InitializeComponent();
        }
        private void button1_Click(object sender, EventArgs e)
        {
            string rawXamlText = File.ReadAllText("in.txt");
            using (var flowDocumentStringReader = new StringReader(rawXamlText))
            using (var flowDocumentTextReader = new XmlTextReader(flowDocumentStringReader))
            {
                if (elementHost != null)
                {
                    Controls.Remove(elementHost);
                    elementHost.Child = null;
                    elementHost.Dispose();
                }
                var uc1 = new UserControl1();
                object document = XamlReader.Load(flowDocumentTextReader);
                var fd = document as FlowDocument;
                uc1.docReader.Document = fd;
                elementHost = new ElementHost();
                elementHost.Dock = DockStyle.Fill;
                elementHost.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
                Controls.Add(elementHost);
                elementHost.Child = uc1;
            }
        }
        private void button2_Click(object sender, EventArgs e)
        {
            if (elementHost != null)
                elementHost.Child = null;
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
        }
    }
}
UserControl1.xaml
<UserControl x:Class="WindowsFormsApplication7.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <FlowDocumentReader x:Name="docReader"></FlowDocumentReader>
</UserControl>
Edit:
I finally have time to deal with this again. What I tried is instead of reusing the ElementHost, disposing and recreating it each time the button is pressed. While this does help a bit, in the sense that the memory is going up and down when you spam click button1 instead of just going up, it still doesn't solve the problem - the memory is going up overall and it is not freed when the form is closed. So now I am putting a bounty up.
As there seems to have been some confusion about what is wrong here, here are the exact steps to reproduce the leak:
1) open task manager
2) click the "START" button to open the form
3) spam a dozen or two clicks on the "GO" button and watch the memory usage - now you should notice the leak
4a) close the form - the memory won't be released.
or
4b) spam the "CLEAN" button a few times, the memory will be released, indicating that this is not a reference leak, it is a GC/finalization problem
What I need to do is prevent the leak at step 3) and free the memory at step 4a). The "CLEAN" button isn't there in the actual application, it is just here to show that there are no hidden references.
I used the CLR profiler to check the memory profile after hitting the "GO" button a few times (memory usage was ~350 MB at this point). It turns out, there were 16125 (5x the amount in the document) Controls.TextBox and 16125 Controls.TextBoxView both rooted in 16125 Documents.TextEditor objects that are rooted in the finalization queue - see here:
https://i.stack.imgur.com/9RBmV.png
Any insight appreciated.
Another update - Solved (kind of)
I just ran into this again in a different, pure WPF application which does not use an ElementHost or a FlowDocument, so in retrospect, the title is misleading. As explained by Anton Tykhyy, this is simply a bug with the WPF TextBox itself, it does not correctly dispose of its TextEditor.
I did not like the workarounds Anton suggested, but his explanation of the bug was useful for my rather ugly, but short solution.
When I am about to destroy an instance of a control that contains TextBoxes, I do this (in the code-behind of the control):
        var textBoxes = FindVisualChildren<TextBox>(this).ToList();
        foreach (var textBox in textBoxes)
        {
            var type = textBox.GetType();
            object textEditor = textBox.GetType().GetProperty("TextEditor", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(textBox, null);
            var onDetach = textEditor.GetType().GetMethod("OnDetach", BindingFlags.NonPublic | BindingFlags.Instance);
            onDetach.Invoke(textEditor, null);
        }
Where FindVisualChildren is:
    public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
    {
        if (depObj != null)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                if (child != null && child is T)
                {
                    yield return (T)child;
                }
                foreach (T childOfChild in FindVisualChildren<T>(child))
                {
                    yield return childOfChild;
                }
            }
        }
    }
Basically, I do what the TextBox should be doing. In the end I also call GC.Collect() (not strictly necessary but helps free the memory faster). This is a very ugly solution but it seems to solve the problem. No more TextEditors stuck in the finalization queue.