大規模PDFでのReadPdf時のメモリピーク

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

大きなPDF全体に対してBarcodeReader.ReadPdf()を一度呼び出すことで、要求されたすべてのページが設定されたDPIでスキャン用にレンダリングされます。そのため、ピークメモリは一定ではなく、ページ数と解像度によってスケールします。 248ページ、80MBのファイルを300DPIで処理する際、メモリは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. 結果リストの事前サイズ設定

結果が追加されると内部の配列が繰り返し倍増するのを避けるため、推定容量で結果リストを初期化します。 再現は、開始の目安としておおよそ10ページごとに1つのバーコードを推定します。

Curtis Chau
テクニカルライター

Curtis Chauは、カールトン大学でコンピュータサイエンスの学士号を取得し、Node.js、TypeScript、JavaScript、およびReactに精通したフロントエンド開発を専門としています。直感的で美しいユーザーインターフェースを作成することに情熱を持ち、Curtisは現代のフレームワークを用いた開発や、構造の良い視覚的に魅力的なマニュアルの作成を楽しんでいます。

開発以外にも、CurtisはIoT(Internet of Things)への強い関心を持ち、ハードウェアとソフトウェアの統合方法を模索しています。余暇には、ゲームをしたりDiscordボットを作成したりして、技術に対する愛情と創造性を組み合わせています。

準備はできましたか?
Nuget ダウンロード 2,317,217 | バージョン: 2026.7 リリースされたばかり
Still Scrolling Icon

まだスクロールしていますか?

すぐに証拠が欲しいですか? PM > Install-Package BarCode
サンプルを実行する 文字列が BarCode になるのを見る。