# Memory Usage and Resource Disposal

> Dispose ServerTextControl and MailMerge, count live instances and USER and GDI handles, switch off AllowUndo and handle OutOfMemory errors in Windows Forms.

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

---

Desktop applications often run all day, and every document they open, merge or convert passes through the memory of one process. TX Text Control releases what an instance holds when the instance is disposed, so most memory problems come from instances that are never disposed, and on Windows those show up as a limit on handles before they show up as a lack of memory. Find out what each part of TX Text Control keeps, how to release it and how to watch for instances your code leaves behind.

### What Holds Memory

| Part | Holds | Released when |
|---|---|---|
| A `TextControl` on a form | Its document, the undo buffer and what it renders for the screen | The control is disposed, together with its form |
| A `ServerTextControl` | Its document, without undo buffer and without rendering | Your code disposes it |
| A `MailMerge` | No document of its own; it works on the document of its `TextComponent` | Your code or the form disposes it |
| Byte arrays and copies your code keeps | Documents in the TX Text Control format, PDF files and other data | Your code removes the last reference |

Each `TextControl` has its own document: a form with two editors keeps two independent documents. A [ServerTextControl](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/servertextcontrol/llms-full.txt) keeps no history for undo and redo and renders no images, which is why Text Control names a smaller memory footprint as one of its advantages over the visible control. Work the user doesn't see belongs there, as [Using ServerTextControl in Desktop Applications](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/servertextcontrol/llms-full.txt) describes.

### Dispose Every ServerTextControl

A `ServerTextControl` must be disposed explicitly: create it in a `using` block, call [Create](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/servertextcontrol/create-method/llms-full.txt) first and check its return value, as [Create and Dispose Each Instance](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/servertextcontrol/#create-and-dispose-each-instance) shows.

> Warning
>
> **Undisposed Instances.** Instances that are never disposed accumulate until `Create` fails. The most common reason for a failing `Create` is that no new window handle can be created: Windows limits a process to 10,000 USER handles and 10,000 GDI handles. An instance whose `Create` returned `false` exists but can't be used; loading a document into it fails with the message "The TXTextControl object must have been completely loaded to use this method." Text Control reports that such failures often appear after an application has run for several days, and sporadically, and that the cause is usually instances that aren't disposed. Restarting the application releases the handles, but disposing the instances is the fix.

The same rule applies to a `MailMerge` that your code creates: it is a component, and a `using` block disposes it, as the samples on [Mail Merge Performance](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/performance/mail-merge/llms-full.txt) do.

### Count Instances and Handles

Text Control's diagnostics sample counts the `ServerTextControl` instances that aren't disposed yet, together with the USER and GDI handles of the process. The following class is based on it. 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 instances through the factory, and show the counters, for example in a `Label` named `statusLabel` after each task:

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

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

The code works as follows:

- `ServerTextControl` is a component and raises the `Disposed` event when it's disposed. The handler decreases the counter; `Interlocked` keeps it correct when several threads create instances.
- `GetGuiResources` from *User32.dll* returns the number of GDI or USER objects of a process, the two counts Windows limits.
- After the `using` block, the instance counter is back where it was. A counter or a handle count that grows while the application runs points to code that doesn't dispose its instances.

The blog article [Diagnostics: When Calling ServerTextControl.Create() Failed](https://www.textcontrol.com/blog/2022/06/29/diagnostics-when-calling-servertextcontrolcreate-fails/) contains the complete sample, which also keeps a list of the live instances and can dispose all of them for debugging.

### Keep the Undo Buffer Small

The editor records every change for undo and redo. [AllowUndo](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/allowundo-property/llms-full.txt) switches this off; the reference recommends it when a `TextControl` is used for tasks such as generating reports, to save time and memory. Switch it on again before the user edits. After your code has loaded or created a document, [ClearUndo](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/clearundo-method/llms-full.txt) empties the buffer. [Undo and Redo](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/editing-text/undo-redo/llms-full.txt) shows both.

### When Memory Runs Out

- **Errors while loading or saving.** A [FilterException](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/filterexception/llms-full.txt) with the [Reason](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/filterexception/reason-property/llms-full.txt) `OutOfMemory` means that TX Text Control couldn't allocate enough memory, and `FileTooBig` that the input file is too big. [Exceptions and Error Handling](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/exceptions/llms-full.txt) shows how to catch them.
- **32-bit processes.** A 64-bit application has more memory available and can open and save much larger documents, as [32-bit and 64-bit Applications](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/installation/requirements/32-bit-64-bit/llms-full.txt) explains.
- **Copies your code keeps.** A byte array with a document stays in memory as long as your code refers to it, for example in a list of recent documents. Keep such copies only as long as you need them, or store them in a file or a database.

### Next Steps

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

---

## Nearby

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