在大型PDF上ReadPdf時的高峰記憶體

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

對於一份整個大型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}")
$vbLabelText   $csharpLabel

每次迭代僅讀取PageNumbers中命名的頁面,因此記憶體在每個塊之間下降,而不是在整個文件中累積。

2. 快取PDF流並重設其位置

在迴圈之前將流讀入本地一次,然後每段重繞它。pdfStream.Seek(0, SeekOrigin.Begin)

3. 一次構建讀取選項

在迴圈外構建PageNumbers,而不是在每次迭代時分配新的選項物件。

4. 預先設定結果列表大小

以預估容量初始化結果列表,以避免結果新增時內部陣列的重複倍增。 重新製作粗略估計每十頁一條條碼作為初始資料。

Curtis Chau
技術作家

Curtis Chau擁有Carleton大學的電腦科學學士學位,專精於前端開發,擁有Node.js、TypeScript、JavaScript和React的專業知識。Curtis熱衷於建立直觀且美觀的使用者介面,喜愛使用現代框架並建立結構良好、視覺吸引力的手冊。

除了開發,Curtis對物聯網(IoT)有濃厚的興趣,探索創新的方法來整合硬體和軟體。在空閒時間,他喜歡玩遊戲和建立Discord機器人,結合他對技術的熱愛與創造力。

準備好開始了嗎?
Nuget 下載 2,317,217 | 版本: 2026.7 剛剛發布
Still Scrolling Icon

還在滾動嗎?

想快速驗證嗎? PM > Install-Package BarCode
運行範例觀看您的字串成為條碼。