Memory Usage
Memory in an application with TX Text Control .NET Server isn't used in one place. ServerTextControl, MailMerge and the Document Viewer work in the process of your application, while every open Document Editor has a worker process of its own in the backend. Knowing which process holds what tells you where memory grows, what releases it and what to watch when an application runs for days or serves many users.
Where Memory Is Used
| Part | Process | Memory is released when |
|---|---|---|
ServerTextControl and MailMerge with their document | Your application | The instance is disposed |
| The Document Viewer | Your application | A request ends; the viewer keeps no state between its requests |
| An editing session of the Document Editor | A worker process of the backend TXTextControl.Web.Server.Core | The editor closes, or a lost connection isn't restored in time |
| Documents your own code keeps, such as copies for auto-saving | Your application | Your code removes them |
Document processing uses the memory of your application's process, so large jobs such as batch merges compete with everything else that runs in the same instance. Editing sessions live in separate processes, and their memory doesn't show in the process of your application. Product Architecture describes the processes.
Dispose Every ServerTextControl
A ServerTextControl holds its resources until it's disposed. Create each instance in a using block, call Create first and let the block dispose it, as Create and Dispose Instances shows. Instances that are never disposed accumulate: on Windows, they are the most common reason why Create returns false after an application has run for some time, because Windows limits a process to 10,000 USER handles and 10,000 GDI handles. Restarting IIS isn't necessary; the handles have to be released.
To find instances that are never disposed, count the live instances. The following factory creates instances and counts them until they're disposed. Create ServerTextControlFactory.cs:
using TXTextControl;
// Creates ServerTextControl instances and counts those that aren't disposed yet
public static class ServerTextControlFactory
{
private static int _liveInstances;
public static int LiveInstances => _liveInstances;
public static ServerTextControl Create()
{
ServerTextControl tx = new ServerTextControl();
Interlocked.Increment(ref _liveInstances);
tx.Disposed += (sender, e) => Interlocked.Decrement(ref _liveInstances);
if (!tx.Create())
{
tx.Dispose();
throw new InvalidOperationException("ServerTextControl could not be created.");
}
return tx;
}
}
Use it wherever your code creates an instance, and log the counter, for example after each request:
using TXTextControl;
using (ServerTextControl tx = ServerTextControlFactory.Create())
{
tx.Load("Documents/contract.docx", StreamType.WordprocessingML);
tx.Save("Documents/contract.pdf", StreamType.AdobePDF);
}
Console.WriteLine($"Live instances: {ServerTextControlFactory.LiveInstances}");
The code works as follows:
ServerTextControlis a .NET component, so it raises theDisposedevent when it's disposed. The handler decreases the counter;Interlockedkeeps it correct when several threads create instances.Createreturnsfalseif the instance couldn't be initialized. The factory disposes the instance and throws, so that no uninitialized instance is used.- After the
usingblock, the counter is back where it was. A counter that keeps growing while the application runs points to code that doesn't dispose its instances.
The blog article Diagnostics: When Calling ServerTextControl.Create() Failed extends the idea with the handle counts of the process on Windows.
Memory of Editing Sessions
Each editor that connects gets a worker process in the backend, which holds its document in memory for as long as the session lasts. Two users who open the same file work on two independent copies. Text Control's sizing guidance is 50 to 150 MB per session, depending on the spell checking dictionaries that are loaded; Size the Document Editor Backend turns it into the size of an instance.
The memory of a session is released when its worker process ends:
- When the editor closes. In single-page applications, call removeFromDom before the view with the editor is removed. It closes the WebSocket connection and removes the editor. The Life of an Editing Session describes the steps.
- When a lost connection isn't restored. After a connection loss, the editor tries to reconnect to its session until the time in reconnectTimeout has passed. Until then, the session and its memory stay on the server.
Fewer sessions need less memory. Text Control recommends a single instance of the editor that moves between the tabs or areas of a page instead of several instances, because one instance needs less memory and performs better. The blog article 5 Layout Patterns for Integrating the TX Text Control Document Editor in ASP.NET Core C# shows such layouts.
Spell Checking Dictionaries
Spell checking in the Document Editor uses TX Spell .NET, whose dictionaries are files on the server. The loaded dictionaries are one reason why a session needs between 50 and 150 MB. getDictionaryList lists the dictionary files and whether each one is loaded, and removeDictionary removes a dictionary from the loaded ones. Deploy the dictionaries of the languages your users write in; Spell Checking in Document Editor describes the setup.
Documents Your Own Code Keeps
Copies of documents that your application keeps in memory count as well. The auto-save sample of the blog article Best Practices: Reliable Auto-Save in TX Text Control Using the WebSocketHandler and Background Services, for example, keeps the latest version of each open document as a byte array, one for each connection, until the connection is unregistered. Remove such copies when the editor closes, or store them outside the process, for example in a database.
Watch the Memory
The parts of TX Text Control run in ordinary processes, and each of them shows its memory:
- Your application shows the memory of
ServerTextControl,MailMergeand the Document Viewer. The counter above tells you whether instances are left behind. - The worker processes of the backend,
TXTextControl.Web.Server.Core.Process.dll, show the memory of the editing sessions, one process for each editor. The backend logs "Starting web editor worker process with connection ID" for each editor that connects. - Memory errors while loading or saving. A FilterException with the Reason
OutOfMemorymeans that TX Text Control couldn't allocate enough memory.
On platforms with a file system in memory, such as Google Cloud Run, files that the application writes use the memory of the instance as well, as Google Cloud notes.
Next Steps
- Container Scaling: size instances for editing sessions and document processing.
- Threading: use
ServerTextControlfrom several threads. - Large Documents: request size limits, long merges and the size of PDF documents.
- Document Editor Architecture: the life of an editing session and its backend.