الذاكرة والبث
Spec: ISO 32000-2, §7.5.4 ISO 32000-2 §7.5.4 Evidence: Mixed evidence
لمحة سريعة
قسم بعنوان «لمحة سريعة»لا ينبغي أن يتطلّب ملف PDF كبير كومة ذاكرة كبيرة. تشرح هذه الصفحة كيف يُبقي NextPDF ذاكرة العملية ضمن حدودها مع نمو المستند، وأين يبثّ إلى القرص بدلاً من أن يراكم البيانات في الذاكرة، وماذا تعني “ميزانية الأداء” هنا: عقد مُتحقَّق منه، لا رقم لافت للنظر.
لماذا يهمّ هذا
قسم بعنوان «لماذا يهمّ هذا»لا يُجبر تنسيق PDF المُولِّد على استخدام كومة ذاكرة كبيرة. ففيه يُسجّل جدول الإحالات المرجعية إزاحة بالبايتات لكل كائن غير مباشر، لذلك يحتاج القارئ إلى وصول عشوائي إلى الملف، لا إلى وجود الملف بأكمله في الذاكرة. يستطيع المُولِّد اتّباع هذا النموذج: يُصدر الكائنات بمجرد اكتمالها ويتذكّر مواضعها فقط. أمّا إذا بقي المستند بأكمله في الكومة حتى الكتابة النهائية، فإن عدد الصفحات يزيد استهلاك الذاكرة خطّياً، وقد يُسقط تقريرٌ لا يسبب مشكلة عند مئة صفحة العمليةَ عند خمسين ألف صفحة.
في أحمال العمل الدفعية وأحمال العمّال، هذا هو الفرق بين خدمة مستقرّة وأخرى تفشل على نحو لا يمكن التنبّؤ به تحت الحِمل. الذاكرة المحدودة خاصّية تصميمية يجب هندستها، لا رقم يُؤمَل الحصول عليه.
النسخة الموجزة
قسم بعنوان «النسخة الموجزة»- صُمِّم كاتب البث بحيث تبقى الذاكرة محدودة لكل مستند. تُكتب كل صفحة إلى المُخرَج بمجرد إنهائها، ثم يُحرَّر مخزّنها المؤقّت.
- يُكتب مسك السجلّات الذي كان سينمو مع عدد الكائنات — إزاحات الإحالات المرجعية وإحالات
Kidsفي شجرة الصفحات — إلى دفقات مؤقّتة مفتوحة باستخدامphp://temp/maxmemory:0، فتنسكب إلى القرص فوراً بدلاً من ملء كومة PHP. - هدف التصميم هو كومة O(1) لكل صفحة: لا يصبح الاحتفاظ بالمستند أكثر كلفةً كلّما أُضيفت الصفحات. هذا هو الهدف الهندسي الذي صيغ الكاتب حوله.
- ميزانية الأداء مفهوم حقيقي ومُهيكَل في نظام التوثيق: حدّ أقصى للزمن الفعلي وحدّ أقصى لذروة الذاكرة، يُعبَّر عنهما بوصفهما عقداً مُتحقَّقاً منه. إنها تنصّ على التزام، وليست نتيجة قياس مرجعي.
- تُعامَل الأرقام الملموسة بوصفها إشارة حيّة، تُقاس وفق طريقة مُعلَنة، لا بوصفها أرقاماً تُجمَّد في النصّ وقد تتقادم في صمت.
كيف يتعامل NextPDF معها
قسم بعنوان «كيف يتعامل NextPDF معها»يتّبع كاتب البث قراراً واحداً: لا تحتفظ أبداً بما تستطيع إصداره.
- 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.
تفصيل الانسكاب إلى القرص هو ما يحمل العبء هنا. يحتفظ php://temp في PHP بقدر ضئيل من البيانات في الذاكرة، ولا ينسكب إلا عندما يتجاوز عتبة معيّنة. يفتح الكاتب تلك الدفقات المؤقّتة بخيار maxmemory:0، الذي يُجبرها على الانسكاب فوراً — فعتبة الذاكرة تساوي صفراً. والأثر العملي هو أن مسك السجلّات لكل كائن، الذي ينمو بحكم تعريفه مع المستند، لا يتراكم أبداً في الكومة. بل يتراكم على القرص، حيث لا يشكّل الحجم قيداً. ومن دون ذلك الخيار، سيتعيّن على نافذة الذاكرة الافتراضية أن تمتلئ قبل الانسكاب، ما يُحبط هدف الذاكرة المحدودة في اللحظة التي يكون فيها أكثر أهمية.
وميزانية الأداء هي النصف الآخر من القصّة. إنها عقد في نظام التوثيق، لا ادّعاء تسويقي. يُعرّف المخطّط الميزانية بوصفها عددين صحيحين محدودين: حدّ أقصى للزمن الفعلي بالميلي ثانية وحدّ أقصى لذروة الذاكرة المقيمة بالميبي بايت. والوصفة التي تُعلن ميزانية تُعلن التزاماً يمكن التحقّق منه، تماماً كما يُعلن التوقيع المُنمَّط التزاماً يستطيع المُصرِّف التحقّق منه. تكمن قيمة الميزانية في كونها مُعلَنة ومفروضة، لا في كونها صغيرة.
ما تقوله الأدلّة
قسم بعنوان «ما تقوله الأدلّة»هذه الصفحة Evidence: Mixed evidence ، وهذا المزج مقصود لأن الأدلّة تنقسم فعلاً إلى ثلاثة أنواع.
- آليّة مسنودة بالشيفرة. يوثّق كاتب البث في
src/Writer/Streaming/StreamingPdfWriter.phpدورة الإصدار-ثم-التحرير لكل صفحة ويُنفّذها، ويفتح دفقات xref وKids الخاصّة به باستخدامphp://temp/maxmemory:0لفرض الانسكاب الفوري إلى القرص حتى تبقى “ذاكرة PHP محدودة بصرف النظر عن عدد الكائنات.” كما أن تصميم البث ذا المؤشّر الواحد، ومن دون الاحتفاظ بالشجرة، هو القرار المعماري المُسجّل أيضاً في ADR-001 (يحتفظ خطّ أنابيب التصيير على الأكثر بحالة O(depth)، لا بعُقد O(n)). - ميزانية بمبدأ تصميمي. حقل
performance_budgetجزء حقيقي واختياري من مخطّط التوثيق، مُعرَّف بوصفه{ wall_ms, peak_mb }بحدود عُليا صريحة. إنه عقد قابل للإنفاذ بحكم التصميم. - القياس المرجعي بوصفه إشارة حيّة. يصرّح ADR-001 بأن أرقام ذروة الذاكرة والزمن الفعلي المضبوطة للمستندات الكبيرة هي هدف تجريبي يُجمَع ويُسجَّل وفق طريقة مُعلَنة — لا رقم يُؤكَّد في النصّ. لذلك تنصّ هذه الصفحة على الآليّة والعقد، وتُحيل الأرقام الملموسة إلى الموضع الذي يقيسها.
يجعل التنسيق هذا الهدف معقولاً، لا طموحاً مجرّداً. ولأن جدول الإحالات المرجعية فهرس إزاحات لكل كائن وفق Spec: ISO 32000-2, §7.5.4 ISO 32000-2 §7.5.4 ، فإن المُولِّد قادر على كتابة الكائنات بمجرد إتمامها والاحتفاظ بإزاحاتها فقط. فالذاكرة المحدودة متّسقة مع تنسيق الملف، لا صراع ضدّه.
مثال عملي
قسم بعنوان «مثال عملي»الذاكرة المحدودة خاصّية لطريقة التوليد، لا راية تضبطها. فحلقة دفعية تُنهي كل مستند وتُحرّره تُبقي الكومة مستقرة طوال التشغيل:
<?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}تُشارَك السجلّات لأن تحليل الخطوط والصور مرّة واحدة هو الغاية من العامل. أمّا المستند فهو غير مُشارَك، ويُحرَّر في كل دورة — وهذا يُبقي ذاكرة الدفعة محدودة بمستند واحد، لا بالدفعة كلّها.
مفهوم خاطئ شائع
قسم بعنوان «مفهوم خاطئ شائع»أكثر المفاهيم الخاطئة شيوعاً هو التعامل مع “الذاكرة المحدودة” بوصفها ادّعاء قياس مرجعي — أي توقّع رقم بالميغابايت يُستشهَد به. وهذا يعكس المقصود. فالضمان هنا بنيوي: صُمِّم الكاتب بحيث لا يصبح الاحتفاظ بالمستند أكثر كلفةً كلّما أُضيفت الصفحات. يعتمد رقم الذروة المحدّد على محتوى الصفحة والخطوط والصور، ولا يكون ذا معنى إلا مع إرفاق طريقة قياسه، ولذلك ينتمي إلى قياس مرجعي لا إلى هذه الجملة.
فخّ ثانٍ: افتراض أن php://temp يحميك بالفعل. إنه يفعل — لكن فقط بعد امتلاء نافذة الذاكرة الافتراضية. خيار maxmemory:0 هو ما يجعل الانسكاب فورياً. وهذا التفصيل هو الآليّة. ومن دونه لن تصمد الخاصّية أمام المستندات الكبيرة ذاتها التي وُجدت من أجلها.
الحدود والتخوم
قسم بعنوان «الحدود والتخوم»تشرح هذه الصفحة آليّة البث ومعنى ميزانية الأداء. وهي لا تنصّ على أرقام مقيسة لذروة الذاكرة أو الإنتاجية. فتلك تُنتجها مُمارسة القياس المرجعي وفق طريقة مُعلَنة، ويُحيل ADR-001 صراحةً الأرقام التجريبية إلى ذلك القياس. إن المحدودية “لكل مستند” لا تعني الثبات بصرف النظر عن محتوى مستند مفرد: فصفحة تحتوي صوراً مضمّنة كبيرة كثيرة تظلّ تكلّف ما تكلّفه تلك الصور. وما لا ينمو هو مسك السجلّات لكل صفحة ورسم الصفحات المُحتفَظ به. ليس كل مسار توليد هو كاتب البث. أما أيّ المسارات يبثّ وأيّها يُخزّن مؤقّتاً، فتحدّده الشيفرة وشكل خطّ الأنابيب، لا هذه النظرة العامّة. إن الآليّة الموصوفة دقيقة اعتباراً من تاريخ مراجعة هذه الصفحة. والمصادر المرجعية هي src/Writer/Streaming/ وADR-001 في مستودع core.
تصميم البث والذاكرة المحدودة خاصّية في Core. والإصدارات لا تُغيّرها:
| Edition | Availability |
|---|---|
| Core | يوفّر Core تصميم الكاتب الباثّ المنسكب إلى القرص. |
| Pro | يرث Pro الكاتب المحدود الذاكرة نفسه؛ فهو يضيف ميزات، لا نموذج ذاكرة مختلفاً. |
| Enterprise | يرث Enterprise الكاتب المحدود الذاكرة نفسه؛ فهو يضيف ميزات، لا نموذج ذاكرة مختلفاً. |
وثائق ذات صلة
قسم بعنوان «وثائق ذات صلة»- نموذج خطّ الأنابيب — موضع مرحلة الكاتب في تدفّق المستند.
- القياس المرجعي الصادق — كيف يُبلّغ NextPDF عن الأرقام التي تتعمّد هذه الصفحة عدم تثبيتها.
- توليد المستندات بحجم كبير — سيناريو الدفعات الذي بُنيت هذه الآليّة لأجله.
مسرد المصطلحات
قسم بعنوان «مسرد المصطلحات»- الذاكرة المحدودة — خاصّية تصميمية لا يستهلك فيها الاحتفاظ بالمستند مزيداً من الكومة كلّما أُضيفت الصفحات (هدف O(1) لكل صفحة).
- كاتب البث — كاتب يُصدر كل صفحة إلى المُخرَج ويُحرّر مخزّنها المؤقّت بدلاً من الاحتفاظ بالمستند بأكمله.
php://temp/maxmemory:0— دفق PHP مؤقّت مُجبَر على الانسكاب إلى القرص فوراً، يُستخدَم لمسك السجلّات المتنامي لكل كائن.- ميزانية الأداء — عقد توثيق مُهيكَل: حدّ أقصى للزمن الفعلي وحدّ أقصى لذروة الذاكرة، مُعلَنان وقابلان للتحقّق.
- الإشارة الحيّة — قيمة مقيسة يُبلَّغ عنها مع طريقتها وفق شروط مُعلَنة، بدلاً من رقم ثابت مُضمَّن في النصّ.