هناك نوعان من لغات البرمجة: لغات البرمجة التي يتم جمعها من البيانات غير المرغوب فيها ولغات البرمجة التي تتطلب إدارة يدوية للذاكرة. ومن أمثلة الأمثلة على ذلك لغة Kotlin أو PHP أو Java. ومن أمثلة ذلك C أو C++ أو Rust. كقاعدة عامة، من المرجح أن تشتمل لغات البرمجة ذات المستوى الأعلى على مجموعة البيانات غير المرغوب فيها كميزة قياسية. سنركّز في مشاركة المدونة هذه على لغات البرمجة التي يتم جمعها من البيانات غير المرغوب فيها وكيفية تجميعها باستخدام WebAssembly (Wasm). ولكن ما هي عملية جمع البيانات المهملة (التي يُشار إليها غالبًا باسم تجميع البيانات المهملة) لتبدأ بها؟
دعم المتصفح
جمع القمامة
بعبارات مبسطة، فكرة جمع البيانات المهملة هي محاولة استعادة الذاكرة التي خصصها البرنامج، ولكن لم تعد تتم الإشارة إليها. تُسمّى هذه الذاكرة "المهملات". هناك العديد من الاستراتيجيات لتنفيذ عملية جمع البيانات غير المرغوب فيها. أحدها هو احتساب المراجع، حيث يكون الهدف هو حساب عدد المراجع إلى العناصر في الذاكرة. وعندما لا يكون هناك مراجع إضافية إلى كائن، يمكن وضع علامة عليه بأنّه لم يعُد مستخدَمًا وبالتالي أصبح جاهزًا لجمع البيانات غير المرغوب فيها. تستخدم أداة تجميع البيانات المهملة في PHP احتساب المراجع، ويتيح لك استخدام وظيفة xdebug_debug_zval()
في إضافة Xdebug إلقاء نظرة سريعة. ضع في الاعتبار برنامج PHP التالي.
<?php
$a= (string) rand();
$c = $b = $a;
$b = 42;
unset($c);
$a = null;
?>
يعيّن البرنامج رقمًا عشوائيًا يتم تحويله إلى سلسلة إلى متغير جديد يُسمى a
. بعد ذلك، يتم إنشاء متغيّرَين جديدَين، وهما b
وc
، وتحديد قيمة a
لهما. بعد ذلك، تتم إعادة تعيين b
إلى الرقم 42
، ثم إلغاء ضبط c
. وأخيرًا، يضبط قيمة a
على null
. عند التعليق التوضيحي على كل خطوة من خطوات البرنامج باستخدام xdebug_debug_zval()
، يمكنك رؤية العدّاد المرجعي لجامع البيانات المهملة أثناء العمل.
<?php
$a= (string) rand();
$c = $b = $a;
xdebug_debug_zval('a');
$b = 42;
xdebug_debug_zval('a');
unset($c);
xdebug_debug_zval('a');
$a = null;
xdebug_debug_zval('a');
?>
في المثال أعلاه، يتم عرض السجلّات التالية، حيث يمكنك معرفة كيفية انخفاض عدد المراجع إلى قيمة المتغيّر a
بعد كل خطوة، وهو أمر منطقي في ضوء تسلسل الرمز. (بالطبع، سيكون الرقم العشوائي مختلفًا).
a:
(refcount=3, is_ref=0)string '419796578' (length=9)
a:
(refcount=2, is_ref=0)string '419796578' (length=9)
a:
(refcount=1, is_ref=0)string '419796578' (length=9)
a:
(refcount=0, is_ref=0)null
هناك تحديات أخرى متعلقة بعملية جمع البيانات غير المرغوب فيها، مثل اكتشاف الدورات، ولكن بالنسبة لهذه المقالة، يكفي الحصول على مستوى أساسي من فهم احتساب المراجع.
يتم تنفيذ لغات البرمجة في لغات برمجة أخرى
قد يبدو الأمر وكأنه بداية، لكن يتم تنفيذ لغات البرمجة بلغات برمجة أخرى. على سبيل المثال، يتم تنفيذ بيئة تشغيل PHP بشكل أساسي بلغة C. يمكنك الاطّلاع على رمز مصدر PHP على GitHub. يوجد رمز مجموعة البيانات غير المرغوب فيها بلغة PHP بشكل أساسي في الملف zend_gc.c
. سيقوم معظم المطورين بتثبيت لغة PHP من خلال مدير الحزم في نظام التشغيل لديهم. مع ذلك، يمكن للمطوّرين أيضًا إنشاء لغة PHP من رمز المصدر. على سبيل المثال، في بيئة Linux، تعمل الخطوات ./buildconf && ./configure && make
على إنشاء لغة PHP لوقت تشغيل Linux. وهذا يعني أيضًا أنّه يمكن تجميع بيئة تشغيل PHP لبيئات تشغيل أخرى، مثل Wasm.
الطرق التقليدية لنقل اللغات إلى بيئة تشغيل Wasm
بصرف النظر عن النظام الأساسي الذي يتم تشغيل PHP عليه، يتم تجميع النصوص البرمجية بلغة PHP في رمز البايت نفسه وتشغيلها من خلال Zend Engine. Zend Engine هو عبارة عن بيئة وقت تشغيل وتجميع للّغات البرمجية بلغة PHP. ويتألف هذا الملخص من جهاز Zend Virtual Machine (VM) الذي يتكون من برنامج Zend Compiler وبرنامج Zend Executor. غالبًا ما يكون للغات مثل PHP التي يتم تنفيذها بلغات أخرى عالية المستوى مثل C تحسينات تستهدف بُنى محددة، مثل Intel أو ARM، وتتطلب خلفية مختلفة لكل بنية. في هذا السياق، يمثل Wasm بنية جديدة. إذا كان الجهاز الافتراضي يتضمّن رمزًا برمجيًا خاصًا بالبنية، مثل التجميع في الوقت المناسب (JIT) أو تجميع البيانات في وقت مبكر (AOT)، سينفّذ مطوّر البرامج أيضًا خلفية لتقنية JIT/AOT للبنية الجديدة. هذا الأسلوب منطقي جدًا لأنه غالبًا ما يمكن إعادة تجميع الجزء الرئيسي من قاعدة الأكواد لكل بنية جديدة.
ونظرًا إلى انخفاض مستوى استخدام Wasm، فمن الطبيعي أن تجرِّب الطريقة نفسها هنا: إعادة تحويل رمز VM الرئيسي باستخدام المحلِّل اللغوي ودعم المكتبة وجمع البيانات غير المرغوب فيها وأداة تحسين البيانات إلى Wasm، واستخدام الواجهة الخلفية JIT أو AOT لـ Wasm إذا لزم الأمر. لقد كان ذلك ممكنًا منذ منتج Wasm MVP، وهو يعمل بشكل جيد في حالات كثيرة. في الواقع، لغة PHP التي تم تجميعها لتطبيق Wasm هي العامل الرئيسي في منصة WordPress. اطّلِع على مزيد من المعلومات عن المشروع في المقالة إنشاء تجارب WordPress ضمن المتصفّح باستخدام WordPress Playground وWebAssembly.
ومع ذلك، يتم تشغيل PHP Wasm في المتصفح في سياق JavaScript للغة المضيف. وفي Chrome، يتم تشغيل JavaScript وWasm في V8، وهو محرّك JavaScript مفتوح المصدر من Google ينفِّذ ECMAScript على النحو المحدَّد في ECMA-262. ويتضمّن المحرِّك V8 حاليًا أداة تجميع للبيانات المهملة. ويعني هذا أنّ المطوّرين، الذين يستخدمون لغة PHP مثلاً التي تم تجميعها إلى Wasm، ينتهي بهم الأمر بشحن تنفيذ أداة تجميع البيانات المهملة (PHP) إلى المتصفح الذي يحتوي فعلاً على أداة تجميع البيانات المهملة، وهو ما قد ينتج عنه هدر كما يبدو. وهنا يأتي دور WasmGC.
المشكلة الأخرى المتمثلة في الأسلوب القديم المتمثل في السماح لوحدات Wasm ببناء تجميع البيانات المهملة الخاص بها أعلى ذاكرة Wasm الخطية هي عدم حدوث تفاعل بعد ذلك بين أداة تجميع البيانات المهملة في Wasm ووحدة تجميع البيانات المهملة المدمجة داخل لغة Wasm، ما يؤدي إلى حدوث مشاكل مثل تسرُّب الذاكرة ومحاولات الجمع غير الفعّالة. يؤدي السماح لوحدات Wasm بإعادة استخدام شبكة GC المدمجة الحالية إلى تجنُّب هذه المشاكل.
نقل لغات البرمجة إلى بيئات تشغيل جديدة باستخدام WasmGC
WasmGC هو اقتراح من منتدى WebAssembly. إنّ تطبيق Wasm MVP الحالي قادر على التعامل فقط مع الأرقام، أي الأعداد الصحيحة والأعداد العشرية، في الذاكرة الخطية، ومع اقتراح أنواع المراجع الذي يتم شحنه، يمكن أن يحتفظ Wasm أيضًا بالمراجع الخارجية. يضيف WasmGC الآن أنواعًا من كومة الذاكرة إلى النظام والصفيف، ما يعني إتاحة تخصيص الذاكرة غير الخطية. يحتوي كل عنصر WasmGC على نوع وبنية ثابتَين، ما يسهّل على الأجهزة الافتراضية إنشاء رمز برمجي فعّال للوصول إلى حقولها بدون المخاطرة بإلغاء التحسين الذي توفّره اللغات الديناميكية، مثل JavaScript. يضيف هذا الاقتراح دعمًا فعالاً للّغات المُدارة عالية المستوى إلى WebAssembly، من خلال أنواع كومة النظام للأجزاء والمصفوفة التي تسمح لبرامج التحويل البرمجي للّغات التي تستهدف Wasm بدمج أداة تجميع البيانات غير المرغوب فيها في الجهاز الافتراضي المضيف. بعبارات مُبسّطة، يعني ذلك أنّه باستخدام بروتوكول WasmGC، يعني نقل لغة برمجة إلى Wasm أنّ أداة تجميع البيانات المهملة بلغة البرمجة لم تعد بحاجة إلى أن تكون جزءًا من المنفذ، ولكن يمكن استخدام أداة تجميع البيانات المهملة الحالية بدلاً من ذلك.
للتحقّق من التأثير الفعلي لهذا التحسين، جمع فريق Wasm في Chrome نُسخًا من مقياس Fannkuch (الذي يخصِّص بنى البيانات أثناء عملها) من C وRust وJava. يمكن أن تتراوح القيم الثنائية C وRust بين 6.1 K و9.6 K اعتمادًا على علامات التجميع المختلفة، في حين أن إصدار Java أصغر بكثير بحجم 2.3 K فقط. لا يشتمل C وRust على أداة تجميع البيانات المهملة، ولكن لا يزالان يجمعان malloc/free
لإدارة الذاكرة، وسبب تصغير Java هنا هو عدم الحاجة إلى تجميع أي رمز لإدارة الذاكرة على الإطلاق. وهذا مجرد مثال محدد، لكنه يبيّن أن برامج WasmGC الثنائية التي من المحتمل أن تكون صغيرة للغاية، وهذا حتى قبل أي عمل مهم على تحسين الحجم.
رؤية استخدام لغة برمجة عبر WasmGC
لغة Kotlin Wasm
من أولى لغات البرمجة التي تم نقلها إلى تطبيق Wasm بفضل WasmGC هي لغة Kotlin على شكل Kotlin/Wasm. يظهر العرض التوضيحي، الذي يتضمّن رمز المصدر المُقدَّم من فريق Kotlin، في البيانات التالية.
import kotlinx.browser.document
import kotlinx.dom.appendText
import org.w3c.dom.HTMLDivElement
fun main() {
(document.getElementById("warning") as HTMLDivElement).style.display = "none"
document.body?.appendText("Hello, ${greet()}!")
}
fun greet() = "world"
قد تتساءل الآن عمّا تعنيه المشكلة، لأنّ رمز Kotlin أعلاه يتألف بشكل أساسي من واجهات برمجة تطبيقات JavaScript OM المحوَّلة إلى Kotlin. وقد أصبح من المنطقي أكثر عند استخدام ميزة Compose Multiplatform، التي تسمح للمطوّرين باستخدام واجهة المستخدم التي سبق أن أنشأوها لتطبيقات Android Kotlin. يمكنك التحقق من ذلك في مرحلة مبكرة من خلال العرض التوضيحي لعارض الصور Kotlin/Wasm واستكشاف رمز المصدر الخاص به، كما كان ذلك من باب المجاملة من فريق Kotlin.
لعبة رمي السهام وFlutter
ويُعِدّ أيضًا فريقا Dart وFlutter في Google الدعم لـ WasmGC. أوشكت عملية التحويل البرمجي لـ Dart-to-Wasm على الانتهاء، ويعمل الفريق على دعم الأدوات لتقديم تطبيقات الويب Flutter المجمَّعة في WebAssembly. ويمكنك الاطّلاع على الحالة الراهنة للعمل في مستندات Flutter. العرض التوضيحي التالي هو معاينة Flutter WasmGC.
مزيد من المعلومات حول WasmGC
لم تجهل مشاركة المدونة هذه أي شيء تقريبًا، وقدّمت في الغالب نظرة عامة عالية المستوى عن WasmGC. لمزيد من المعلومات عن هذه الميزة، راجع الروابط التالية:
- طريقة جديدة لاستخدام WebAssembly في طريقة جديدة لدمج لغات البرمجة غير الضرورية
- نظرة عامة على WasmGC
- WasmGC MVP
- فعالية WasmGC بعد الحصول على منتج الحد الأدنى (MVP)
شكر وتقدير
صورة رئيسية من تصميم غاري تشان على Unإعادة البداية تمت مراجعة هذه المقالة بواسطة ماتياس ليدتك وآدم كلاين وجوشوا بيل وألون زاكاي وجاكوب كومروف وكليمنس باكس وإيمانويل زيغلر ورايشيل أندرو.