How to Control Parallel OCR Memory Usage in C#

Each page processed in parallel by IronOCR allocates its own native Tesseract engine instance. For large batches - hundreds of pages from a scanned PDF or a folder of images - memory consumption scales linearly with the number of concurrent pages. The IronTesseract.MaxDegreeOfParallelism property caps how many pages are OCR'd at the same time within a single Read call, and IronTesseract.MultiThreaded switches to fully sequential processing when set to false.

Quickstart: Cap Parallel OCR with MaxDegreeOfParallelism

Set a single property to bound how many pages IronOCR reads at once, keeping peak memory inside a known budget.

  1. Install IronOCR with NuGet Package Manager

    PM > Install-Package IronOcr
  2. Copy and run this code snippet.

    var ocr = new IronOcr.IronTesseract { MaxDegreeOfParallelism = 4 };
  3. Deploy to test on your live environment

    Start using IronOCR in your project today with a free trial

    arrow pointer


NuGet Install with NuGet

PM >  Install-Package IronOcr

Check out IronOCR on NuGet for quick installation. With over 10 million downloads, it’s transforming PDF development with C#. You can also download the DLL or Windows installer.

Why Does OCR Memory Grow During Large Batches?

When MultiThreaded is true, which is the default, IronOCR processes pages in parallel. Each concurrent page spins up its own native Tesseract engine holding image buffers, recognition models, and intermediate state in unmanaged memory.

Peak memory for a Read call therefore has two parts, and only one of them is under your control:

  • A fixed cost for the document itself, which grows with the number of pages regardless of how they are scheduled.
  • A marginal cost for each page read concurrently, one native engine apiece.

MaxDegreeOfParallelism acts on the second term only. That distinction matters: on a long document the fixed cost can be the larger share, so capping parallelism reduces peak memory substantially without ever driving it to zero.

In containerized environments - Docker with fixed --memory limits, Kubernetes pods with resource quotas - the marginal term is what turns a working job into an OOM kill, because it scales with the host's logical processor count rather than with anything you configured. On bare-metal servers it causes swapping and degrades throughput. We cap parallelism to keep the peak working set within a known budget.

How Much Memory Does Each Concurrent Page Use?

Measured against the reference workload below, those two terms come out as:

peak ≈ fixed document cost + (per-engine cost × concurrency)

Take the measured figures as a starting point and measure your own workload to refine them - both terms move with DPI, page complexity, document length, and language pack.

How Was This Measured?

  • Each configuration ran in its own process with the EnglishFast language pack, after a single-page warm-up, five times over.
  • Memory is the median of those runs; throughput is the fastest.

Separate processes matter because peak memory is a high-water mark that never resets - a second configuration measured in the same process would re-report the first one's peak. Throughput uses the fastest run rather than the median because other work on the machine can only ever slow a read down, never speed it up.

The corpus is "Experiences in Biodiversity Research: A Field Course" by Thea B. Gessler, Iowa State University - a 49-page text-dense PDF, downloadable so results can be reproduced. The same runs also confirmed every row of the precedence table further down this page.

What Were the Results?

MaxDegreeOfParallelism Peak memory Marginal cost per added page Throughput
Sequential - MultiThreaded = false 782 MB baseline 0.77 pages/s
2 859 MB +77 MB 1.32 pages/s
4 1008 MB +75 MB 2.09 pages/s
8 1279 MB +68 MB 2.56 pages/s
16 - the default on this machine 1829 MB +69 MB 3.01 pages/s

Tested on: 8-core / 16-thread x64 laptop CPU · 1.9 GHz · 16 GB RAM · Windows 11 x64 · .NET 8 · IronOCR 2026.8.1 · last verified August 2026

The first row turns parallelism off altogether; the last is what you get by setting nothing. Peak memory is the highest the process reached at any single moment. Marginal cost per added page is the extra memory each additional concurrent page cost over the row above it - it stays close to flat down the whole column, and that steadiness is what makes the model worth planning against.

Please noteRun-to-run variation was under 2% on every configuration. Peak working set is recorded per process, so the memory column is unaffected by other software running at the time; throughput is not, so treat it as specific to this hardware.

Where Do Diminishing Returns Start?

Memory grows steadily with concurrency. Throughput does not - the gains flatten out while the memory cost keeps climbing at the same rate. Compare the last two rows: the memory column rises far more sharply between them than the throughput column does.

That is the practical finding: the default is rarely the best trade for batch work. It is tuned for latency on a single document, not for footprint. If you are processing documents in bulk on a memory-constrained host, an explicit cap somewhere below the logical processor count will usually cost you very little speed and save a great deal of memory. Measure where the knee falls on your own documents, because it moves with page complexity.

How Do I Cap How Many Pages Are Read at Once?

Set IronTesseract.MaxDegreeOfParallelism to the maximum number of pages that should process concurrently within a single Read call. Left alone, it defaults to Environment.ProcessorCount.

using IronOcr;
using System;

var ocr = new IronTesseract();

// Cap concurrency at 2 pages. Each concurrent page holds its own native
// engine, so this bounds peak memory for every Read on this instance.
ocr.MaxDegreeOfParallelism = 2;

// The cap applies per Read call, however many pages the document has.
using var input = new OcrInput();
input.LoadPdf("500-page-archive.pdf");

OcrResult result = ocr.Read(input);
Console.WriteLine(result.Text.Length);
using IronOcr;
using System;

var ocr = new IronTesseract();

// Cap concurrency at 2 pages. Each concurrent page holds its own native
// engine, so this bounds peak memory for every Read on this instance.
ocr.MaxDegreeOfParallelism = 2;

// The cap applies per Read call, however many pages the document has.
using var input = new OcrInput();
input.LoadPdf("500-page-archive.pdf");

OcrResult result = ocr.Read(input);
Console.WriteLine(result.Text.Length);
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

What Value Should I Choose?

Size it against the two-part model above rather than picking a number:

fixed document cost + per-engine cost × MaxDegreeOfParallelismmemory budget for OCR

To fill in the two costs for your own documents, read a representative file twice - once with MultiThreaded set to false, once with MaxDegreeOfParallelism = 2 - and record the peak working set each time. The sequential run gives you the fixed cost; the difference between the two gives you the cost of one extra engine. The reference figures for both are in the table above.

Two things worth noting when you apply it. The fixed term scales with document length, so a long archive will not behave like the sample measured above. And leave headroom for the .NET runtime, the managed heap, and anything else in the process - reserving around 40% of the container limit is a reasonable starting point.

Memory-generous hosts can leave the default in place. Constrained ones should cap explicitly, and as the diminishing-returns figures above show, that cap often costs far less throughput than its memory saving suggests.

WarningMaxDegreeOfParallelism bounds pages within one Read call only. If your own code also runs several documents at once, the two multiply - four concurrent documents against a default of 16 is 64 engines, not 16. Cap both layers. See High Peak Memory During Bulk OCR for the outer-loop pattern.

How Do I Read Pages Sequentially?

Set MultiThreaded to false. This is the lowest-memory option, because only one native engine is ever active. The trade-off is throughput: a batch takes roughly N times longer than with N concurrent workers.

using IronOcr;

var ocr = new IronTesseract();

// One page at a time. Overrides MaxDegreeOfParallelism, whatever it is set to.
ocr.MultiThreaded = false;

using var input = new OcrInput();
input.LoadPdf("scans.pdf");

OcrResult result = ocr.Read(input);
using IronOcr;

var ocr = new IronTesseract();

// One page at a time. Overrides MaxDegreeOfParallelism, whatever it is set to.
ocr.MultiThreaded = false;

using var input = new OcrInput();
input.LoadPdf("scans.pdf");

OcrResult result = ocr.Read(input);
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

WarningMultiThreaded had no effect before this release - it is now a live setting. Code that set it to false expecting a no-op will read sequentially after upgrading, with no compiler warning and no exception. Review existing usages if throughput drops unexpectedly.

How Do the Two Properties Interact?

MultiThreaded MaxDegreeOfParallelism Effective concurrency
true (default) Not set Environment.ProcessorCount
true A positive number That number of concurrent pages
true 0 or negative Falls back to Environment.ProcessorCount
false Any value 1 - sequential, MaxDegreeOfParallelism is ignored

TipsEnvironment.ProcessorCount reports logical processors, not physical cores. On a machine with simultaneous multithreading the default is twice the core count - an 8-core CPU defaults to 16 concurrent pages, not 8. Size your memory budget against the logical count.

Can I Bound Memory During Page Orientation Detection?

The new overload of OcrInput.DetectPageOrientation accepts a maxDegreeOfParallelism parameter that caps how many pages are orientation-detected concurrently. Non-positive values fall back to Environment.ProcessorCount. The single-argument overload is unchanged and remains source and binary compatible.

using IronOcr;
using System;

using var input = new OcrInput();
input.LoadPdf("rotated-scans.pdf");

// Analyse at most 2 pages at once. Orientation detection runs before the
// OCR read, so capping it here prevents a spike ahead of the real workload.
var results = input.DetectPageOrientation(
    OrientationDetectionMode.Fast,
    maxDegreeOfParallelism: 2);

// One result per page, in page order.
foreach (var result in results)
{
    Console.WriteLine($"Page {result.PageNumber}: {result.RotationAngle}");
}
using IronOcr;
using System;

using var input = new OcrInput();
input.LoadPdf("rotated-scans.pdf");

// Analyse at most 2 pages at once. Orientation detection runs before the
// OCR read, so capping it here prevents a spike ahead of the real workload.
var results = input.DetectPageOrientation(
    OrientationDetectionMode.Fast,
    maxDegreeOfParallelism: 2);

// One result per page, in page order.
foreach (var result in results)
{
    Console.WriteLine($"Page {result.PageNumber}: {result.RotationAngle}");
}
IRON VB CONVERTER ERROR developers@ironsoftware.com
$vbLabelText   $csharpLabel

Fast mode reuses one engine per worker thread instead of allocating one per page, which reduces peak memory further. This matters when orientation detection runs as a preprocessing step before the main OCR read, since capping parallelism here prevents a memory spike before the real workload begins.

Does Parallel OCR Still Crash on Large Batches?

Previous versions could throw a fatal AccessViolationException during parallel or high-volume OCR due to unsafe cross-thread access to native Tesseract state. That exception is unrecoverable - it terminates the process without a catch opportunity. It is now resolved. The previous workarounds, one IronTesseract instance per thread and one document at a time, are no longer necessary: the engine isolates native state per worker correctly, and MaxDegreeOfParallelism provides an official cap that replaces those ad-hoc patterns.

When Should I Tune These Settings?

  • Container or CI runner with a memory cap - set MaxDegreeOfParallelism to keep peak memory within the limit.
  • Batch processing thousands of pages - lower MaxDegreeOfParallelism to prevent OOM kills. Throughput decreases proportionally, but the job completes instead of crashing.
  • Lowest possible memory - set MultiThreaded to false for sequential mode. One engine, one page at a time.
  • Maximum throughput - leave both at their defaults so the engine uses all available cores. See the multithreading for speed example.
  • Accuracy versus speed tuning - that is a different axis. The tune Tesseract for speed guide covers accuracy and speed trade-offs, while this page covers memory and throughput trade-offs.

For async and responsiveness concerns, such as keeping a UI responsive during OCR, see the async OCR how-to, which owns ReadAsync and OcrReadTask. This page covers resource bounding: keeping memory consumption predictable regardless of batch size.

Explore the IronTesseract configuration guide for the full property surface, loading PDF inputs and loading image inputs for OcrInput usage patterns, and page orientation detection for the DetectPageOrientation method and its new parallelism overload.

Explore IronOCR licensing options to move from trial to production.

Frequently Asked Questions

What is OCR and why is it important?

OCR, or Optical Character Recognition, is a technology that converts different types of documents, such as scanned paper documents, PDFs, or images captured by a digital camera, into editable and searchable data. OCR is important because it automates data extraction, reduces manual data entry, and makes information easily accessible and editable.

How does IronOCR enhance the OCR process?

IronOCR enhances the OCR process by providing accurate and high-speed text recognition capabilities. It supports multiple languages and includes features like image pre-processing to improve text recognition accuracy.

Can IronOCR handle multi-page documents?

Yes, IronOCR can process multi-page documents efficiently, extracting text from each page and allowing users to work with the entire document as a cohesive unit.

What file formats does IronOCR support?

IronOCR supports a wide range of file formats including PDF, TIFF, JPEG, PNG, and BMP, allowing flexibility in the types of documents it can process.

Is IronOCR suitable for recognizing text in low-quality images?

Yes, IronOCR includes advanced image pre-processing features that enhance the quality of low-resolution or poor-quality images, increasing the accuracy of text recognition.

Does IronOCR support multiple languages?

IronOCR supports multiple languages, making it a versatile tool for global applications that require text recognition in different languages.

Can IronOCR be integrated into existing applications?

IronOCR is designed to be easily integrated into existing applications using C#, allowing developers to add OCR functionality to their software with minimal effort.

What are the benefits of using IronOCR for document management?

Using IronOCR for document management streamlines the workflow by converting scanned documents into searchable and editable text, reducing the need for manual data entry and improving document accessibility.

How can IronOCR improve data accuracy?

IronOCR improves data accuracy through its advanced recognition algorithms and image correction features, ensuring that the text extraction process is both reliable and precise.

Is there a free trial available for IronOCR?

Yes, Iron Software offers a free trial of IronOCR, allowing users to test its features and capabilities before making a purchase decision.

Curtis Chau
Technical Writer

Curtis Chau holds a Bachelor’s degree in Computer Science (Carleton University) and specializes in front-end development with expertise in Node.js, TypeScript, JavaScript, and React. Passionate about crafting intuitive and aesthetically pleasing user interfaces, Curtis enjoys working with modern frameworks and creating well-structured, visually appealing manuals.

...

Read More
Ready to Get Started?
Nuget Downloads 6,224,182 | Version: 2026.8 just released
Still Scrolling Icon

Still Scrolling?

Want proof fast? PM > Install-Package IronOcr
run a sample watch your image become searchable text.