هناك نوعان من لغات البرمجة: لغات البرمجة التي تجمع المهملات ولغات البرمجة التي تتطلّب إدارة الذاكرة يدويًا. ومن الأمثلة على هذه الفئة، من بين غيرها الكثير، Kotlin أو PHP أو Java. ومن الأمثلة على هذه الفئة C أو C++ أو Rust. كقاعدة عامة، من المرجّح أن تتضمّن لغات البرمجة ذات المستوى الأعلى ميزة جمع المهملات كميزة قياسية. في هذه المشاركة على المدوّنة، يتم التركيز على لغات البرمجة التي تتضمّن ميزة جمع المهملات وكيفية تجميعها إلى WebAssembly (Wasm). ولكن ما هو جمع المهملات (المعروف غالبًا باسم GC)؟
توافق المتصفّح
جمع البيانات المهملة
بعبارة مبسطة، تتمثل فكرة جمع المهملات في محاولة استرداد الذاكرة التي خصصها البرنامج، ولكن لم يعُد يتمّ الرجوع إليها. وتُعرف هذه الذاكرة باسم "الذاكرة المهملة". هناك العديد من الاستراتيجيات لتنفيذ عملية جمع المهملات. ومن هذه الأساليب احتساب عدد الإشارات حيث يكون الهدف هو احتساب عدد الإشارات إلى العناصر في الذاكرة. عندما لا تتوفّر أيّ إشارات إلى عنصر، يمكن وضع علامة عليه بأنّه لم يعُد مُستخدَمًا، وبالتالي يكون جاهزًا لجمع المهملات. يستخدم برنامج جمع المهملات في 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. محرك Zend هو مُجمِّع وبيئة وقت التشغيل للغة البرمجة PHP. وتتكوّن من Zend Virtual Machine (الآلة الافتراضية)، التي تتكوّن من Zend Compiler وZend Executor. إنّ اللغات، مثل PHP التي يتم تنفيذها بلغات أخرى عالية المستوى مثل C، تتضمّن عادةً تحسينات تستهدف بنى أساسية معيّنة، مثل Intel أو ARM، وتتطلّب واجهة خلفية مختلفة لكل بنية أساسية. في هذا السياق، يمثّل Wasm بنية جديدة. إذا كان الجهاز الافتراضي يتضمّن رمزًا برمجيًا خاصًا بالبنية، مثل التجميع أثناء التشغيل (JIT) أو التجميع مسبقًا (AOT)، ينفّذ المطوّر أيضًا واجهة خلفية لاستخدام ميزة التجميع أثناء التشغيل/التجميع مسبقًا للبنية الجديدة. ويُعدّ هذا النهج منطقيًا جدًا لأنّه في أغلب الأحيان يمكن إعادة تجميع الجزء الرئيسي من قاعدة البيانات لكل بنية جديدة.
نظرًا لمستوى Wasm المنخفض، من الطبيعي تجربة النهج نفسه هنا: إعادة تجميع رمز وحدة المحاكاة الافتراضية الرئيسية مع المُحلِّل ودعم المكتبة وجمع المهملات والمحسِّن إلى Wasm، وتنفيذ خلفية JIT أو AOT لـ Wasm إذا لزم الأمر. وقد أصبح ذلك ممكنًا منذ إصدار Wasm MVP، وهو يعمل بشكل جيد في العديد من الحالات. في الواقع، PHP المجمّعة إلى Wasm هي ما يشغّل WordPress Playground. يمكنك الاطّلاع على مزيد من المعلومات عن المشروع في المقالة إنشاء تجارب 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 بإعادة استخدام ميزة "جمع القمامة" المضمّنة الحالية إلى تجنُّب هذه المشاكل.
نقل لغات البرمجة إلى بيئات تشغيل جديدة باستخدام WasmGC
WasmGC هو اقتراح لمجموعة منتدى WebAssembly. لا يمكن لتنفيذ Wasm MVP الحالي التعامل إلا مع الأرقام، أي الأعداد الصحيحة والكسور العشرية، في الذاكرة الخطية، ومع اقتراح أنواع المراجع الذي يتم إرساله، يمكن أن يحتفظ Wasm أيضًا بالمراجع الخارجية. تضيف WasmGC الآن أنواعًا من بنية البيانات وأنواعًا من مجموعات الذاكرة، ما يعني توفُّر إمكانية تخصيص الذاكرة غير الخطية. يحتوي كل عنصر WasmGC على نوع وبنية ثابتَين، ما يسهّل على الأجهزة الافتراضية إنشاء رمز فعّال للوصول إلى حقولها بدون المخاطرة بعمليات إزالة التحسين التي تُجريها اللغات الديناميكية مثل JavaScript. وبالتالي، يضيف هذا الاقتراح دعمًا فعّالاً للغات المُدارة عالية المستوى إلى WebAssembly، وذلك من خلال أنواع هياكل البيانات وأنواع أكوام الصفائف التي تتيح لمُجمِّعي اللغات الذين يستهدفون Wasm الدمج مع أداة جمع المهملات في الآلة الافتراضية المضيف. بعبارة مبسطة، يعني ذلك أنّ استخدام WasmGC لنقل لغة برمجة إلى Wasm يعني أنّه لم يعد من الضروري أن يكون أداة جمع المهملات في لغة البرمجة جزءًا من عملية النقل، بل يمكن استخدام أداة جمع المهملات الحالية بدلاً من ذلك.
للتأكّد من التأثير الفعلي لهذا التحسين، جمع فريق Wasm في Chrome إصدارات من مقياس أداء Fannkuch (الذي يخصّص بنى البيانات أثناء عمله) من C وRust وJava. يمكن أن تتراوح أحجام الملفات الثنائية لـ C وRust بين 6.1 كيلوبايت و9.6 كيلوبايت، وذلك استنادًا إلى علامات المُجمِّع المختلفة، في حين أنّ حجم إصدار Java أصغر بكثير، إذ يبلغ 2.3 كيلوبايت فقط. لا تتضمّن لغة 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.
Dart وFlutter
تعمل فِرق Dart وFlutter في Google أيضًا على توفير دعم لـ WasmGC. اكتملت تقريبًا عملية تجميع Dart إلى WebAssembly، ويعمل الفريق على توفير أدوات لاستخدام تطبيقات الويب من Flutter التي تم تجميعها إلى WebAssembly. يمكنك الاطّلاع على الحالة الحالية للعمل في مستندات Flutter. العرض التجريبي التالي هو معاينة Flutter WasmGC.
مزيد من المعلومات حول WasmGC
لم يقدّم منشور المدونة هذا سوى نظرة عامة على WasmGC، وركّز على الغالب على تقديم نظرة عامة عالية المستوى حوله. لمزيد من المعلومات عن هذه الميزة، يُرجى الاطّلاع على الروابط التالية:
- طريقة جديدة لاستخدام لغات البرمجة التي تتضمّن ميزة جمع المهملات بكفاءة في WebAssembly
- نظرة عامة على WasmGC
- إصدار WasmGC العلني
- WasmGC بعد إطلاق المنتج النموذجي
الشكر والتقدير
تمت مراجعة هذه المقالة من قِبل ماتياس ليدتك وآدم كلاين وجوشوا بيل وألون زاكي وجاكوب كوميروف وكليمنس باكيس وإيمانويل زيغلر وراشيل أندرو.