在大型PDF上ReadPdf時的高峰記憶體
對於一份整個大型PDF調用BarcodeReader.ReadPdf()一次,將以配置的DPI渲染每個請求的頁面進行掃描,因此記憶體峰值隨頁數和解析度而增加,而不是保持不變。 在一個248頁、80MB的檔案中,300 DPI下,記憶體介於3GB和8GB之間,甚至達到12GB,足以在記憶體有限的環境中失敗。
BarcodeReader.ReadPdf()在一次操作中處理每個傳遞給它的頁面。 當一次讀取大型高DPI文件的完整頁面範圍時,所有頁面都會一起留在記憶體中,因此峰值使用隨頁面組的大小增長。 這反映了讀取是如何分批的,而不是IronBarcode中的確認缺陷。
解決方案
1. 固定頁塊讀取
使用chunkSize可以降低記憶體峰值,但會增加更多傳遞,因此應根據環境的記憶體上限進行調整。
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}")
每次迭代僅讀取PageNumbers中命名的頁面,因此記憶體在每個塊之間下降,而不是在整個文件中累積。
2. 快取PDF流並重設其位置
在迴圈之前將流讀入本地一次,然後每段重繞它。pdfStream.Seek(0, SeekOrigin.Begin)。
3. 一次構建讀取選項
在迴圈外構建PageNumbers,而不是在每次迭代時分配新的選項物件。
4. 預先設定結果列表大小
以預估容量初始化結果列表,以避免結果新增時內部陣列的重複倍增。 重新製作粗略估計每十頁一條條碼作為初始資料。

