Pico Alto de Memória Durante Leitura de PDFs em PDF Grandes
Chamar BarcodeReader.ReadPdf() uma vez para um PDF grande renderiza cada página solicitada para escaneamento no DPI configurado, assim a memória de pico escala com a contagem de páginas e resolução em vez de se manter plana. Em um arquivo de 248 páginas, 80MB a 300 DPI, a memória variava entre 3GB e 8GB com picos de até 12GB, o suficiente para falhar em ambientes com limitação de memória.
BarcodeReader.ReadPdf() processa cada página entregue a ele em uma única operação. Quando o intervalo completa de páginas de um documento grande e de alta resolução é lido de uma vez, todas essas páginas são mantidas na memória juntas, então o uso de pico cresce com o tamanho do conjunto de páginas. Isso reflete como a leitura é empacotada, não um defeito confirmado no IronBarcode.
Solução
1. Leia em pedaços de página fixos
Divida o documento em pedaços de página fixos com PdfBarcodeReaderOptions.PageNumbers para que apenas um pedaço esteja na memória por vez. Um chunkSize menor reduz a memória de pico, mas adiciona mais passagens, então ajuste-o ao limite de memória do ambiente.
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}")
Cada iteração lê apenas as páginas nomeadas em PageNumbers, então a memória cai entre os pedaços em vez de se acumular no arquivo inteiro.
2. Armazene em cache o fluxo de PDF e redefina sua posição
Leia o fluxo em um local uma vez antes do loop, em seguida, rebobine-o por pedaço. A propriedade Stream pode alocar em cada acesso, então armazene-a em var pdfStream = pdf.Stream; e chame pdfStream.Seek(0, SeekOrigin.Begin) antes de cada leitura de pedaço.
3. Construa as opções do leitor uma vez
Construa PdfBarcodeReaderOptions fora do loop e mude apenas PageNumbers por pedaço, em vez de alocar um novo objeto de opções a cada iteração.
4. Pré-dimensione a lista de resultados
Inicialize a lista de resultados com uma capacidade estimada para evitar a duplicação repetida do array interno à medida que os resultados são adicionados. A reprodução estima aproximadamente um código de barras para cada dez páginas como ponto de partida.

