Geheugen en streaming
Spec: ISO 32000-2, §7.5.4 ISO 32000-2 §7.5.4 Evidence: Mixed evidence
In een oogopslag
Sectie met titel “In een oogopslag”Een groot PDF-bestand zou geen grote heap moeten vereisen. Deze pagina legt uit hoe NextPDF het procesgeheugen binnen grenzen houdt terwijl een document groeit, waar het naar schijf streamt in plaats van gegevens in het geheugen te laten ophopen, en wat een „performance budget” hier betekent: een controleerbaar contract, geen pakkend benchmarkcijfer.
Waarom dit belangrijk is
Sectie met titel “Waarom dit belangrijk is”Het PDF-formaat verplicht een generator niet om een grote heap te gebruiken. De cross-referencetabel legt voor elk indirect object een byte-offset vast, zodat een lezer willekeurige toegang tot het bestand nodig heeft, niet het hele bestand in het geheugen. Een generator kan dat model volgen: objecten uitschrijven zodra ze klaar zijn en alleen bewaren waar ze terecht zijn gekomen. Als het hele document daarentegen tot de laatste schrijfactie in de heap blijft, laat het aantal pagina’s het geheugengebruik lineair groeien en kan een rapport dat bij honderd pagina’s nog prima werkt het proces bij vijftigduizend pagina’s laten vastlopen.
Voor batch- en workerworkloads is dit het verschil tussen een stabiele service en een service die onder belasting onvoorspelbaar uitvalt. Begrensd geheugen is een ontwerpeigenschap die bewust wordt ontworpen, geen gehoopt getal.
De korte versie
Sectie met titel “De korte versie”- De streaming writer is zo opgezet dat het geheugen per document begrensd blijft. Elke pagina wordt naar de uitvoer geschreven zodra die is afgerond. Daarna wordt de bijbehorende buffer vrijgegeven.
- De administratie die anders met het aantal objecten zou meegroeien — de cross-referenceoffsets en de
Kids-verwijzingen van de paginaboom — wordt naar tijdelijke streams geschreven. Die worden metphp://temp/maxmemory:0geopend en schrijven daardoor onmiddellijk naar schijf in plaats van de PHP-heap te vullen. - Het ontwerpdoel is O(1) heap per pagina: het vasthouden van het document kost niet méér heap naarmate er pagina’s worden toegevoegd. Dat is het technische doel waarop de writer is gebaseerd.
- Een performance budget is in het documentatiesysteem een echt, gestructureerd concept: een limiet op de kloktijd en een limiet op het piekgeheugen, uitgedrukt als een controleerbaar contract. Het legt een verplichting vast. Het is geen benchmarkresultaat.
- Concrete cijfers worden behandeld als een levend signaal, gemeten volgens een vastgelegde methode, en niet als prozatekst vastgezet waar ze ongemerkt kunnen verouderen.
Hoe NextPDF dit aanpakt
Sectie met titel “Hoe NextPDF dit aanpakt”De streaming writer volgt één leidend principe: houd nooit vast wat ook kan worden uitgeschreven.
- Start page A single active cursor; no document-wide page graph in memory.
- Finalise page Page content + page object written straight to the output stream.
- Release buffer The finalised page buffer is dropped; the heap returns to baseline.
- Record offset to disk Xref and Kids entries go to php://temp/maxmemory:0 — immediate disk spill.
- Close Pages-tree root, Catalog, and trailer written once at the end.
De manier waarop naar schijf wordt weggeschreven, is het dragende detail. De PHP-stream php://temp houdt een kleine hoeveelheid gegevens in het geheugen en schrijft pas naar schijf wanneer een drempel wordt overschreden. De writer opent die tijdelijke streams met de optie maxmemory:0, waardoor ze onmiddellijk naar schijf wegschrijven: de geheugendrempel is nul. Het praktische effect is dat de administratie per object, die per definitie met het document meegroeit, zich nooit in de heap ophoopt. Ze groeit op schijf, waar de omvang niet de beperkende factor is. Zonder die optie zou het standaardvenster in het geheugen eerst moeten vollopen voordat er naar schijf wordt weggeschreven. Dat doet het doel van begrensd geheugen juist teniet op het moment dat het er het meest toe doet.
Het performance budget is de andere helft van het verhaal. Het is een contract binnen het documentatiesysteem, geen marketingclaim. Het schema definieert een budget met twee begrensde gehele getallen: een limiet op de kloktijd in milliseconden en een limiet op het piek-residentgeheugen in mebibytes. Een recipe dat een budget declareert, legt daarmee een controleerbare verplichting vast, net zoals een getypeerde signature een verplichting vastlegt die een compiler kan controleren. De waarde van een budget ligt in het feit dat het is vastgelegd en wordt afgedwongen, niet in hoe klein het is.
Wat de feiten zeggen
Sectie met titel “Wat de feiten zeggen”Deze pagina gebruikt Evidence: Mixed evidence , en die mengeling is bewust gekozen omdat de feiten daadwerkelijk in drie soorten uiteenvallen.
- Door code onderbouwd mechanisme. De streaming writer in
src/Writer/Streaming/StreamingPdfWriter.phpdocumenteert en implementeert per pagina de cyclus van uitschrijven en daarna vrijgeven. Hij opent zijn xref- en Kids-streams metphp://temp/maxmemory:0om onmiddellijk wegschrijven naar schijf af te dwingen, zodat „het PHP-geheugen begrensd blijft ongeacht het aantal objecten.” Het ontwerp met streaming, één cursor en geen vastgehouden boom is ook de architectuurbeslissing die in ADR-001 is vastgelegd (de weergavepijplijn houdt hoogstens O(depth)-status vast, geen O(n)-knooppunten). - Budget als ontwerpprincipe. Het veld
performance_budgetis een echt, optioneel onderdeel van het documentatieschema, gedefinieerd als{ wall_ms, peak_mb }met expliciete bovengrenzen. Door zijn opzet is het een afdwingbaar contract. - Benchmark als levend signaal. ADR-001 stelt expliciet dat de gecontroleerde piekgeheugen- en kloktijdcijfers voor grote documenten een empirisch doel zijn dat volgens een vastgelegde methode wordt verzameld en vastgelegd: geen getal dat in proza wordt beweerd. Deze pagina beschrijft daarom het mechanisme en het contract, en verwijst voor concrete cijfers naar de plek waar ze worden gemeten.
Het formaat maakt dit doel realistisch, niet alleen ambitieus. Omdat de cross-referencetabel een offsetindex per object is volgens Spec: ISO 32000-2, §7.5.4 ISO 32000-2 §7.5.4 , is een generator in staat om objecten weg te schrijven zodra ze zijn afgerond en alleen hun offsets te bewaren. Begrensd geheugen past bij het bestandsformaat en is er niet mee in strijd.
Praktijkvoorbeeld
Sectie met titel “Praktijkvoorbeeld”Begrensd geheugen is een eigenschap van hóé er wordt gegenereerd, geen instelbare vlag. Een batchlus die elk document afrondt en vrijgeeft, houdt de heap gedurende de hele uitvoering vlak:
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\DocumentFactory;use NextPDF\Core\PdfFactory;use NextPDF\Graphics\ImageRegistry;use NextPDF\Typography\FontRegistry;
// Process-lifetime, shared once.$factory = PdfFactory::new() ->withCompress(true) ->withDocumentFactory(new DocumentFactory( new FontRegistry(), new ImageRegistry(maxCacheBytes: 50 * 1024 * 1024), ));
// Per-document, created and released each iteration.foreach ($invoiceBatch as $invoice) { $doc = $factory->create(); $doc->addPage(); $doc->writeHtml($invoice->toHtml()); $doc->save($invoice->outputPath()); unset($doc); // the document model is not carried into the next iteration}De registers worden gedeeld, omdat lettertypen en afbeeldingen één keer parsen juist het doel van een worker is. Het document wordt niet gedeeld en wordt bij elke doorgang vrijgegeven. Daardoor blijft het batchgeheugen begrensd door één document en niet door de hele batch.
Veelvoorkomend misverstand
Sectie met titel “Veelvoorkomend misverstand”Het meest voorkomende misverstand is „begrensd geheugen” lezen als een benchmarkclaim: een megabytegetal verwachten om te citeren. Dat draait de boodschap om. De garantie is hier structureel: de writer is zo gebouwd dat het vasthouden van een document niet méér heap kost naarmate er pagina’s worden toegevoegd. Een specifiek piekcijfer hangt af van de pagina-inhoud, lettertypen en afbeeldingen, is alleen betekenisvol met de bijbehorende meetmethode en hoort daarom thuis bij een benchmark, niet in deze zin.
Een tweede valkuil is aannemen dat php://temp al bescherming biedt. Dat doet het, maar pas nadat het standaardvenster in het geheugen vol is. De optie maxmemory:0 maakt het wegschrijven naar schijf onmiddellijk. Dat detail ís het mechanisme. Zonder die optie houdt de eigenschap juist niet stand bij de grote documenten waarvoor ze bestaat.
Grenzen en beperkingen
Sectie met titel “Grenzen en beperkingen”Deze pagina legt het streamingmechanisme en de betekenis van een performance budget uit. Ze vermeldt geen gemeten piekgeheugen- of doorvoercijfers. Die worden volgens een vastgelegde methode geproduceerd door de benchmarkingdiscipline, en ADR-001 verwijst empirische getallen uitdrukkelijk naar die meting. Begrensd „per document” betekent niet constant ongeacht de inhoud van een afzonderlijk document: een pagina met veel grote ingesloten afbeeldingen kost nog steeds wat die afbeeldingen kosten. Wat niet groeit, is de administratie per pagina en de vastgehouden paginagraaf. Niet elk generatiepad is de streaming writer. Welke paden streamen en welke bufferen, wordt bepaald door de code en de vorm van de pijplijn, niet door dit overzicht. Het beschreven mechanisme is correct op de beoordelingsdatum van deze pagina. De gezaghebbende bronnen zijn src/Writer/Streaming/ en ADR-001 in de core-repository.
Het ontwerp met streaming en begrensd geheugen is een eigenschap van Core. Edities veranderen dat niet:
| Edition | Availability |
|---|---|
| Core | Core levert het ontwerp van de streaming writer die naar schijf wegschrijft. |
| Pro | Pro erft dezelfde writer met begrensd geheugen; het voegt functies toe, geen ander geheugenmodel. |
| Enterprise | Enterprise erft dezelfde writer met begrensd geheugen; het voegt functies toe, geen ander geheugenmodel. |
Gerelateerde documentatie
Sectie met titel “Gerelateerde documentatie”- Het pijplijnmodel — waar de writer-fase zich in de documentstroom bevindt.
- Eerlijk benchmarken — hoe NextPDF de getallen rapporteert die deze pagina bewust niet als claim opvoert.
- Documentgeneratie op grote schaal — het batchscenario waarvoor dit mechanisme is gebouwd.
Verklarende woordenlijst
Sectie met titel “Verklarende woordenlijst”- Begrensd geheugen — een ontwerpeigenschap waarbij het vasthouden van het document niet méér heap verbruikt naarmate er pagina’s worden toegevoegd (het O(1)-per-paginadoel).
- Streaming writer — de writer die elke pagina naar de uitvoer schrijft en de buffer ervan vrijgeeft in plaats van het hele document vast te houden.
php://temp/maxmemory:0— een tijdelijke PHP-stream die wordt gedwongen onmiddellijk naar schijf weg te schrijven, gebruikt voor de groeiende administratie per object.- Performance budget — een gestructureerd documentatiecontract: een limiet op de kloktijd en een limiet op het piekgeheugen, vastgelegd en controleerbaar.
- Levend signaal — een gemeten waarde die met de bijbehorende methode onder vastgelegde omstandigheden wordt gerapporteerd, in plaats van een vast getal dat in proza staat.