# Memory Usage and Resource Disposal

> Find undisposed ServerTextControl instances in WPF apps, watch USER and GDI handles, see why the WPF TextControl needs no Dispose, and handle OutOfMemory.

- **Product:** TX Text Control .NET for WPF
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET for WPF > Performance > Memory Usage and Resource Disposal
- **2283 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/memory-usage/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/memory-usage/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/memory-usage/llms-full.txt

---

The garbage collector of .NET frees objects that nobody refers to any more, but it doesn't decide when a `ServerTextControl` gives back what it holds in Windows. That is the job of your code, and in a WPF application that runs for a whole working day, an instance that is never disposed adds up. What follows shows what each part of TX Text Control keeps in memory, which ones your code has to dispose, and how to find the instances that are left behind before Windows runs out of handles.

### What Each Part Keeps

| Part | Keeps | What your code does |
|---|---|---|
| The WPF `TextControl` in a window | Its document, the undo buffer and what it renders for the screen | Nothing to dispose: the control doesn't implement `IDisposable`. Keep the undo buffer small, as described below |
| A `ServerTextControl` | Its document, without undo buffer and without rendering | Dispose it, in a `using` block |
| A `MailMerge` | No document of its own; it merges into the document of its `TextComponent` | Dispose it; it is a component |
| Byte arrays and copies of documents | Whatever your code stores in them | Drop the reference when the copy isn't needed any more |

A [ServerTextControl](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/servertextcontrol/llms-full.txt) keeps no undo history and renders no images, and Text Control names its smaller memory footprint as one of its advantages over a visible control. Documents the user doesn't see are therefore best created there, as [Using ServerTextControl in Desktop Applications](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-processing/servertextcontrol/llms-full.txt) describes.

### Dispose Every ServerTextControl

Text Control states that a `ServerTextControl` must be disposed explicitly and recommends a `using` block, which disposes the instance even when an exception leaves it; [Create and Dispose Each Instance](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-processing/servertextcontrol/#create-and-dispose-each-instance) shows the pattern.

> Warning
>
> **Undisposed Instances.** When instances aren't disposed, [Create](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/servertextcontrol/create-method/llms-full.txt) eventually returns `false`. The most typical cause is that no new window handle can be created, because Windows allows a process 10,000 USER handles and 10,000 GDI handles. The instance then exists but can't be used, and loading a document into it fails with "The TXTextControl object must have been completely loaded to use this method." Text Control describes such failures as appearing after days and sporadically, and names instances that weren't disposed as their most likely cause. A restart of the application releases the handles; disposing the instances prevents the problem.

A `MailMerge` that your code creates is disposed the same way, in a `using` block, as the samples of [Mail Merge Performance](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/mail-merge/llms-full.txt) show.

### Watch Instances and Handles

To find instances that are never disposed, count them. The following class, based on Text Control's diagnostics sample, creates `ServerTextControl` instances, counts those not yet disposed and reads the USER and GDI handles of the process. Add it to your project as *ServerTextControlFactory.cs*:

```csharp
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using TXTextControl;

// Creates ServerTextControl instances and counts those that aren't disposed yet
public static class ServerTextControlFactory
{
    private static int liveInstances;

    [DllImport("User32")]
    private static extern int GetGuiResources(IntPtr hProcess, int uiFlags);

    public static int LiveInstances => liveInstances;

    // 0 counts GDI objects, 1 counts USER objects
    public static int GdiHandles => GetGuiResources(Process.GetCurrentProcess().Handle, 0);
    public static int UserHandles => GetGuiResources(Process.GetCurrentProcess().Handle, 1);

    public static ServerTextControl Create()
    {
        ServerTextControl tx = new ServerTextControl();

        if (!tx.Create())
        {
            tx.Dispose();
            throw new InvalidOperationException("ServerTextControl could not be created.");
        }

        Interlocked.Increment(ref liveInstances);
        tx.Disposed += (sender, e) => Interlocked.Decrement(ref liveInstances);

        return tx;
    }
}
```

Create your instances through the factory, and show the counters, for example in a `TextBlock` named `statusText` at the bottom of *MainWindow.xaml*:

```csharp
private void Convert_Click(object sender, RoutedEventArgs e)
{
    using (ServerTextControl tx = ServerTextControlFactory.Create())
    {
        tx.Load("contract.docx", StreamType.WordprocessingML);
        tx.Save("contract.pdf", StreamType.AdobePDF);
    }

    statusText.Text = $"Instances: {ServerTextControlFactory.LiveInstances}, " +
        $"USER handles: {ServerTextControlFactory.UserHandles}, " +
        $"GDI handles: {ServerTextControlFactory.GdiHandles}";
}
```

The code works as follows:

- As a component, `ServerTextControl` raises its `Disposed` event when it is disposed, and the handler lowers the counter. `Interlocked` keeps the count right when background threads create instances.
- `GetGuiResources` of *User32.dll* returns the number of GDI objects or USER objects of the process, the two resources Windows limits.
- A counter that stays above zero after the work is done, or handle counts that keep rising, point to instances that are never disposed.

The blog article [Diagnostics: When Calling ServerTextControl.Create() Failed](https://www.textcontrol.com/blog/2022/06/29/diagnostics-when-calling-servertextcontrolcreate-fails/) contains the original sample, which also lists the live instances and can dispose all of them while you debug.

### Keep the Undo Buffer Small

The WPF `TextControl` records every change so that the user can undo it, and the buffer grows with each change. Switch it off while your code generates a document, and empty it after your code has loaded one; [Undo and Redo](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-editor/editing-text/undo-redo/#switch-the-buffer-off) shows how.

### When Memory Runs Out

- **Errors while loading or saving.** A [FilterException](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/filterexception/llms-full.txt) whose [Reason](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/filterexception/reason-property/llms-full.txt) is `OutOfMemory` means that TX Text Control couldn't allocate enough memory; `FileTooBig` means that the input file is too big. [Exceptions and Error Handling](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-processing/exceptions/llms-full.txt) shows how to catch a `FilterException`.
- **A 32-bit process.** A 64-bit build has far more memory available; [32-bit and 64-bit Applications](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/installation/requirements/32-bit-64-bit/llms-full.txt) shows how to configure it.
- **Documents in view models.** A document kept as a byte array in a view model, a list of recent files or an auto-save copy stays in memory as long as something refers to it. Store such copies in a file or a database when they aren't needed right away.

### Next Steps

- [Large Documents](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/large-documents/llms-full.txt) — build and process long documents efficiently.
- [Background Operations](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/background-operations/llms-full.txt) — one `ServerTextControl` per thread.
- [Using ServerTextControl in Desktop Applications](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-processing/servertextcontrol/llms-full.txt) — create and dispose instances.
- [Performance Best Practices](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/best-practices/llms-full.txt) — all measures at a glance.

---

## Nearby

- **Previous:** [Large Documents](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/large-documents/llms-full.txt)
- **Next:** [Document Loading and Conversion](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/performance/loading-conversion/llms-full.txt)
