Pamięć i strumieniowanie
Spec: ISO 32000-2, §7.5.4 ISO 32000-2 §7.5.4 Evidence: Mixed evidence
W skrócie
Dział zatytułowany „W skrócie”Duży plik PDF nie powinien wymagać dużej sterty. Ta strona wyjaśnia, jak NextPDF utrzymuje ograniczone zużycie pamięci procesu, gdy dokument rośnie, kiedy strumieniuje dane na dysk zamiast gromadzić je w pamięci i co oznacza tutaj „budżet wydajności”: sprawdzalne zobowiązanie, a nie liczba do nagłówka.
Dlaczego to ma znaczenie
Dział zatytułowany „Dlaczego to ma znaczenie”Format PDF nie wymusza na generatorze używania dużej sterty. Tablica odsyłaczy zapisuje przesunięcie bajtowe dla każdego obiektu pośredniego, więc czytnik potrzebuje dostępu swobodnego do pliku, a nie całego pliku w pamięci. Generator może działać według tego samego modelu: emitować obiekty w miarę ich ukończenia i zapamiętywać tylko, gdzie zostały zapisane. Jeśli natomiast cały dokument pozostaje na stercie aż do końcowego zapisu, liczba stron liniowo zwiększa zużycie pamięci, a raport, który działa poprawnie przy stu stronach, doprowadza proces do awarii przy pięćdziesięciu tysiącach.
W przypadku obciążeń wsadowych i procesów roboczych jest to różnica między stabilną usługą a usługą, która zawodzi pod obciążeniem w nieprzewidywalny sposób. Ograniczone zużycie pamięci to właściwość projektowa, którą trzeba świadomie zaprojektować, a nie liczba, na którą można liczyć.
W skrócie najważniejsze
Dział zatytułowany „W skrócie najważniejsze”- Zapisujący strumieniowo jest zbudowany tak, aby pamięć pozostawała ograniczona na dokument. Każda strona jest zapisywana do wyjścia, gdy tylko zostanie sfinalizowana, a potem jej bufor zostaje zwolniony.
- Ewidencja, która w przeciwnym razie rosłaby wraz z liczbą obiektów — przesunięcia odsyłaczy oraz odwołania
Kidsdrzewa stron — jest zapisywana do strumieni tymczasowych otwieranych zphp://temp/maxmemory:0, które od razu zrzucają dane na dysk, zamiast zapełniać stertę PHP. - Cel projektowy to O(1) sterty na stronę: przechowywanie dokumentu nie kosztuje więcej w miarę dodawania stron. To cel inżynieryjny, według którego ukształtowano zapisujący.
- W systemie dokumentacji realnym, ustrukturyzowanym pojęciem jest budżet wydajności: limit czasu rzeczywistego oraz limit szczytowego zużycia pamięci, wyrażone jako sprawdzalne zobowiązanie. Określa zobowiązanie. Nie jest wynikiem testu wydajności.
- Konkretne liczby są traktowane jako żywy sygnał, mierzony zgodnie z określoną metodą, a nie jako wartości zamrożone w treści, gdzie mogłyby po cichu się zdezaktualizować.
Jak podchodzi do tego NextPDF
Dział zatytułowany „Jak podchodzi do tego NextPDF”Zapisujący strumieniowo kieruje się jedną zasadą: nigdy nie przechowuj tego, co możesz wyemitować.
- 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.
Kluczowy jest szczegół dotyczący zrzutu na dysk. Mechanizm php://temp w PHP przechowuje niewielką ilość danych w pamięci i zrzuca je na dysk dopiero po przekroczeniu progu. Zapisujący otwiera te strumienie tymczasowe z opcją maxmemory:0, która wymusza ich natychmiastowy zrzut na dysk — próg pamięciowy wynosi zero. W praktyce ewidencja na poziomie obiektu, która z definicji rośnie wraz z dokumentem, nigdy nie gromadzi się na stercie. Gromadzi się na dysku, gdzie rozmiar nie stanowi ograniczenia. Bez tej opcji domyślne okno pamięciowe musiałoby się zapełnić, zanim nastąpiłby zrzut, co niweczyłoby cel ograniczonego zużycia pamięci dokładnie wtedy, gdy ma to największe znaczenie.
Drugą częścią tego obrazu jest budżet wydajności. To zobowiązanie systemu dokumentacji, a nie deklaracja marketingowa. Schemat definiuje budżet jako dwie ograniczone liczby całkowite: limit czasu rzeczywistego w milisekundach oraz limit szczytowej pamięci rezydentnej w mebibajtach. Przepis, który deklaruje budżet, deklaruje zobowiązanie możliwe do sprawdzenia, tak samo jak sygnatura z typami deklaruje zobowiązanie możliwe do sprawdzenia przez kompilator. Wartość budżetu polega na tym, że jest określony i egzekwowany, a nie na tym, że jest mały.
Co mówią dowody
Dział zatytułowany „Co mówią dowody”Ta strona ma status Evidence: Mixed evidence i jest to zamierzone, ponieważ dowody są naprawdę trojakiego rodzaju.
- Mechanizm poparty kodem. Zapisujący strumieniowo w
src/Writer/Streaming/StreamingPdfWriter.phpdokumentuje i implementuje cykl emitowania i zwalniania na poziomie strony oraz otwiera swoje strumienie xref i Kids zphp://temp/maxmemory:0, aby wymusić natychmiastowy zrzut na dysk, dzięki czemu „pamięć PHP pozostaje ograniczona niezależnie od liczby obiektów.” Strumieniowy projekt z pojedynczym kursorem i bez zachowywanego drzewa to także decyzja architektoniczna zapisana w ADR-001 (potok renderowania przechowuje co najwyżej stan O(głębokość), a nie O(n) węzłów). - Budżet jako zasada projektowa. Pole
performance_budgetto rzeczywista, opcjonalna część schematu dokumentacji, zdefiniowana jako{ wall_ms, peak_mb }z jawnymi górnymi limitami. Z założenia jest egzekwowalnym zobowiązaniem. - Test wydajności jako żywy sygnał. ADR-001 jednoznacznie stwierdza, że kontrolowane wartości szczytowej pamięci i czasu rzeczywistego dla dużych dokumentów stanowią cel empiryczny do zebrania i zapisania zgodnie z określoną metodą — a nie liczbę do zadeklarowania w treści. Dlatego ta strona opisuje mechanizm i zobowiązanie, a konkretne wartości odsyła do miejsca, które je mierzy.
Format sprawia, że cel jest racjonalny, a nie aspiracyjny. Ponieważ tablica odsyłaczy jest indeksem przesunięć na poziomie obiektu zgodnie z Spec: ISO 32000-2, §7.5.4 ISO 32000-2 §7.5.4 , generator jest w stanie zapisywać obiekty po ich ukończeniu i zachowywać tylko ich przesunięcia. Ograniczone zużycie pamięci jest zgodne z formatem pliku, a nie walką z nim.
Praktyczny przykład
Dział zatytułowany „Praktyczny przykład”Ograniczone zużycie pamięci to właściwość sposobu generowania, a nie flaga do ustawienia. Pętla wsadowa, która finalizuje i zwalnia każdy dokument, utrzymuje stertę na stałym poziomie przez cały przebieg:
<?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}Rejestry są współdzielone, ponieważ jednorazowe przetworzenie czcionek i obrazów ma sens właśnie w procesie roboczym. Dokument nie jest współdzielony i jest zwalniany w każdej iteracji — dzięki czemu pamięć wsadu jest ograniczona rozmiarem jednego dokumentu, a nie całego wsadu.
Częste nieporozumienie
Dział zatytułowany „Częste nieporozumienie”Najczęstszym nieporozumieniem jest traktowanie „ograniczonego zużycia pamięci” jako deklaracji wynikającej z testu wydajności i oczekiwanie liczby w megabajtach, którą można zacytować. To odwraca sens tego, co tu powiedziano. Gwarancja jest tutaj strukturalna: zapisujący jest zbudowany tak, że przechowywanie dokumentu nie kosztuje więcej w miarę dodawania stron. Konkretna wartość szczytowa zależy od zawartości strony, czcionek i obrazów i ma sens tylko wraz z dołączoną metodą pomiaru, dlatego należy do testu wydajności, a nie do tego zdania.
Druga pułapka: założenie, że php://temp już cię chroni. Chroni — ale dopiero po zapełnieniu domyślnego okna pamięciowego. Dopiero opcja maxmemory:0 sprawia, że zrzut jest natychmiastowy. Ten szczegół jest właśnie mechanizmem. Bez niej ta właściwość nie utrzymałaby się właśnie przy dużych dokumentach, dla których istnieje.
Ograniczenia i granice
Dział zatytułowany „Ograniczenia i granice”Ta strona wyjaśnia mechanizm strumieniowania oraz znaczenie budżetu wydajności. Nie podaje zmierzonych wartości szczytowej pamięci ani przepustowości. Powstają one w ramach dyscypliny testów wydajności zgodnie z zadeklarowaną metodą, a ADR-001 jednoznacznie pozostawia liczby empiryczne temu pomiarowi. Ograniczenie „na dokument” nie oznacza stałej wartości niezależnej od zawartości pojedynczego dokumentu: strona z wieloma dużymi osadzonymi obrazami nadal kosztuje tyle, ile kosztują te obrazy. Tym, co nie rośnie, jest ewidencja na poziomie strony oraz zachowywany graf stron. Nie każda ścieżka generowania to zapisujący strumieniowo. O tym, które ścieżki strumieniują, a które buforują, decyduje kod i kształt potoku, a nie ten przegląd. Opisany mechanizm odzwierciedla stan na datę przeglądu tej strony. Miarodajnymi źródłami są src/Writer/Streaming/ oraz ADR-001 w repozytorium core.
Projekt strumieniowania i ograniczonego zużycia pamięci jest właściwością wydania Core. Wydania tego nie zmieniają:
| Edition | Availability |
|---|---|
| Core | Core dostarcza projekt zapisującego, który strumieniuje dane i zrzuca je na dysk. |
| Pro | Pro dziedziczy ten sam zapisujący o ograniczonym zużyciu pamięci; dodaje funkcje, a nie inny model pamięci. |
| Enterprise | Enterprise dziedziczy ten sam zapisujący o ograniczonym zużyciu pamięci; dodaje funkcje, a nie inny model pamięci. |
Powiązana dokumentacja
Dział zatytułowany „Powiązana dokumentacja”- Model potoku — miejsce etapu zapisującego w przepływie dokumentu.
- Uczciwe testy wydajności — jak NextPDF raportuje liczby, których ta strona celowo nie deklaruje.
- Generowanie dokumentów w dużej skali — scenariusz wsadowy, dla którego zbudowano ten mechanizm.
Słowniczek
Dział zatytułowany „Słowniczek”- Ograniczone zużycie pamięci — właściwość projektowa oznaczająca, że przechowywanie dokumentu nie zużywa więcej sterty w miarę dodawania stron (cel O(1) na stronę).
- Zapisujący strumieniowo — zapisujący, który emituje każdą stronę do wyjścia i zwalnia jej bufor, zamiast zachowywać cały dokument.
php://temp/maxmemory:0— strumień tymczasowy PHP zmuszony do natychmiastowego zrzutu na dysk, używany do rosnącej ewidencji na poziomie obiektu.- Budżet wydajności — ustrukturyzowane zobowiązanie dokumentacji: limit czasu rzeczywistego oraz limit szczytowego zużycia pamięci, jawnie określone i sprawdzalne.
- Żywy sygnał — mierzona wartość raportowana wraz ze swoją metodą w określonych warunkach, a nie stała liczba osadzona w treści.