Consommation de mémoire maximale lors de la lecture de PDF sur de gros PDFs

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

Appeler BarcodeReader.ReadPdf() une fois pour un gros PDF entier rend chaque page demandée pour l'analyse au DPI configuré, donc la mémoire de pointe évolue avec le nombre de pages et la résolution au lieu de rester stable. Sur un fichier de 248 pages, 80Mo à 300 DPI, la mémoire allait de 3Go à 8Go avec des pointes à 12Go, suffisantes pour échouer dans des environnements à mémoire limitée.

BarcodeReader.ReadPdf() traite chaque page qui lui est remise en une seule opération. Lorsque la plage entière de pages d'un document large et de haute DPI est lue à la fois, toutes ces pages sont maintenues en mémoire ensemble, donc l'utilisation de pointe augmente avec la taille de l'ensemble de pages. Ceci reflète comment la lecture est regroupée, pas un défaut confirmé dans IronBarcode.

Solution

1. Lire par tranches de pages fixes

Divisez le document en morceaux de pages fixes avec PdfBarcodeReaderOptions.PageNumbers afin qu'un seul morceau soit en mémoire à la fois. Un plus petit chunkSize réduit la mémoire de pointe mais ajoute plus de passages, il faut donc l'adapter au plafond de mémoire de l'environnement.

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

Chaque itération ne lit que les pages nommées dans PageNumbers, donc la mémoire diminue entre les morceaux plutôt que de s'accumuler sur l'ensemble du fichier.

2. Mettre en cache le flux PDF et réinitialiser sa position

Lisez le flux dans une variable locale une fois avant la boucle, puis rembobinez-le par morceau. La propriété Stream peut s'allouer à chaque accès, alors stockez celle-ci dans var pdfStream = pdf.Stream; et appelez pdfStream.Seek(0, SeekOrigin.Begin) avant chaque lecture de morceau.

3. Construire les options de lecteur une fois

Construisez PdfBarcodeReaderOptions en dehors de la boucle et ne changez que PageNumbers par morceau, plutôt que d'allouer un nouvel objet d'options à chaque itération.

4. Pré-dimensionner la liste des résultats

Initialisez la liste des résultats avec une capacité estimée pour éviter le doublement interne répété du tableau au fur et à mesure que les résultats sont ajoutés. La repro estime environ un code-barres par dix pages comme point de départ.

Curtis Chau
Rédacteur technique

Curtis Chau détient un baccalauréat en informatique (Université de Carleton) et se spécialise dans le développement front-end avec expertise en Node.js, TypeScript, JavaScript et React. Passionné par la création d'interfaces utilisateur intuitives et esthétiquement plaisantes, Curtis aime travailler avec des frameworks modernes ...

Lire la suite
Prêt à commencer?
Nuget Téléchargements 2,317,217 | Version : 2026.7 vient de sortir
Still Scrolling Icon

Vous faites encore défiler ?

Vous voulez une preuve rapidement ? PM > Install-Package BarCode
exécuter un échantillon regarder votre chaîne devenir un code-barres.