Pico Alto de Memoria al Leer PDF en Archivos PDF Grandes

This article was translated from English: Does it need improvement?
Translated
View the article in English

Llamar a BarcodeReader.ReadPdf() una vez para todo un PDF grande renderiza cada página solicitada para escanear a la DPI configurada, por lo que la memoria máxima escala con el conteo de páginas y la resolución en lugar de mantenerse constante. En un archivo de 248 páginas y 80 MB a 300 DPI, la memoria osciló entre 3GB y 8GB con picos de hasta 12GB, suficiente para fallar en entornos con limitaciones de memoria.

BarcodeReader.ReadPdf() procesa cada página entregada en una sola operación. Cuando se lee al completo el rango de páginas de un documento grande, alta DPI, todas esas páginas se mantienen juntas en memoria, de modo que el uso máximo crece con el tamaño del conjunto de páginas. Esto refleja cómo se agrupan las lecturas, no un defecto confirmado en IronBarcode.

Solución

1. Leer en fragmentos de páginas fijos

Divide el documento en fragmentos de páginas fijas con PdfBarcodeReaderOptions.PageNumbers para que solo un fragmento esté en memoria a la vez. Un chunkSize más pequeño reduce la memoria máxima pero agrega más pasadas, así que ajústalo al límite de memoria del entorno.

var barcodeMetadata = new List<BarcodeResult>();
var pageChunks = Enumerable.Range(1, pdf.PageCount)
    .GroupBy(i => i / 50)
    .Select(g => g.ToArray())
    .ToList();
foreach (var chunk in pageChunks)
{
    var readerOptions = new PdfBarcodeReaderOptions
    {
        ExpectMultipleBarcodes = true,
        ExpectBarcodeTypes = IronBarCode.BarcodeEncoding.AllOneDimensional,
        Speed = ReadingSpeed.Detailed,
        ScanMode = BarcodeScanMode.OnlyDetectionModel,
        DPI = 300,
        PageNumbers = chunk
    };
    Console.WriteLine($"Processing pages: Pages {chunk.First()}-{chunk.Last()}");
    var chunkResult = BarcodeReader.ReadPdf(pdf.Stream, readerOptions);
    if (chunkResult != null && chunkResult.Count > 0)
    {
        barcodeMetadata.AddRange(chunkResult);
    }
    // Optional memory pressure relief
    GC.Collect();
    GC.WaitForPendingFinalizers();
}
Console.WriteLine($"Total barcodes found: {barcodeMetadata.Count}");
var barcodeMetadata = new List<BarcodeResult>();
var pageChunks = Enumerable.Range(1, pdf.PageCount)
    .GroupBy(i => i / 50)
    .Select(g => g.ToArray())
    .ToList();
foreach (var chunk in pageChunks)
{
    var readerOptions = new PdfBarcodeReaderOptions
    {
        ExpectMultipleBarcodes = true,
        ExpectBarcodeTypes = IronBarCode.BarcodeEncoding.AllOneDimensional,
        Speed = ReadingSpeed.Detailed,
        ScanMode = BarcodeScanMode.OnlyDetectionModel,
        DPI = 300,
        PageNumbers = chunk
    };
    Console.WriteLine($"Processing pages: Pages {chunk.First()}-{chunk.Last()}");
    var chunkResult = BarcodeReader.ReadPdf(pdf.Stream, readerOptions);
    if (chunkResult != null && chunkResult.Count > 0)
    {
        barcodeMetadata.AddRange(chunkResult);
    }
    // Optional memory pressure relief
    GC.Collect();
    GC.WaitForPendingFinalizers();
}
Console.WriteLine($"Total barcodes found: {barcodeMetadata.Count}");
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports IronBarCode

Dim barcodeMetadata As New List(Of BarcodeResult)()
Dim pageChunks = Enumerable.Range(1, pdf.PageCount) _
    .GroupBy(Function(i) i \ 50) _
    .Select(Function(g) g.ToArray()) _
    .ToList()

For Each chunk In pageChunks
    Dim readerOptions As New PdfBarcodeReaderOptions With {
        .ExpectMultipleBarcodes = True,
        .ExpectBarcodeTypes = BarcodeEncoding.AllOneDimensional,
        .Speed = ReadingSpeed.Detailed,
        .ScanMode = BarcodeScanMode.OnlyDetectionModel,
        .DPI = 300,
        .PageNumbers = chunk
    }
    Console.WriteLine($"Processing pages: Pages {chunk.First()}-{chunk.Last()}")
    Dim chunkResult = BarcodeReader.ReadPdf(pdf.Stream, readerOptions)
    If chunkResult IsNot Nothing AndAlso chunkResult.Count > 0 Then
        barcodeMetadata.AddRange(chunkResult)
    End If
    ' Optional memory pressure relief
    GC.Collect()
    GC.WaitForPendingFinalizers()
Next

Console.WriteLine($"Total barcodes found: {barcodeMetadata.Count}")
$vbLabelText   $csharpLabel

Cada iteración solo lee las páginas nombradas en PageNumbers, por lo que la memoria disminuye entre fragmentos en lugar de acumularse en todo el archivo.

2. Caché del flujo PDF y restablece su posición

Lee el flujo en una variable local antes del bucle, luego rebobínalo por fragmento. La propiedad Stream puede asignar memoria en cada acceso, así que almacénala en var pdfStream = pdf.Stream; y llama a pdfStream.Seek(0, SeekOrigin.Begin) antes de cada lectura de fragmento.

3. Construir las opciones del lector una vez

Construye PdfBarcodeReaderOptions fuera del bucle y cambia solo PageNumbers por fragmento, en lugar de asignar un nuevo objeto de opciones en cada iteración.

4. Pre-tamaño de la lista de resultados

Inicializa la lista de resultados con una capacidad estimada para evitar duplicar internamente una matriz repetidamente a medida que se añaden resultados. La repro estima aproximadamente un código de barras por cada diez páginas como cifra inicial.

Curtis Chau
Escritor Técnico

Curtis Chau tiene una licenciatura en Ciencias de la Computación (Carleton University) y se especializa en el desarrollo front-end con experiencia en Node.js, TypeScript, JavaScript y React. Apasionado por crear interfaces de usuario intuitivas y estéticamente agradables, disfruta trabajando con frameworks modernos y creando manuales bien ...

Leer más
¿Listo para empezar?
Nuget Descargas 2,317,217 | Versión: 2026.7 recién lanzado
Still Scrolling Icon

¿Aún desplazándote?

¿Quieres una prueba rápida? PM > Install-Package BarCode
ejecuta una muestra observa cómo tu cadena se convierte en un código de barras.