هناك نوعان من لغات البرمجة: لغات البرمجة التي يتم فيها جمع البيانات غير المرغوب فيها ولغات البرمجة التي تتطلّب إدارة الذاكرة يدويًا. من الأمثلة على ذلك، بالإضافة إلى العديد من الأمثلة الأخرى، Kotlin أو PHP أو Java. ومن الأمثلة على ذلك C أو C++ أو Rust. كقاعدة عامة، من المرجّح أن تتضمّن لغات البرمجة ذات المستوى الأعلى ميزة جمع البيانات غير المرغوب فيها كميزة عادية. في مشاركة المدونة هذه، سنركّز على لغات البرمجة التي يتم جمع البيانات غير المرغوب فيها فيها وكيفية تجميعها إلى WebAssembly (Wasm). ولكن ما هي عملية جمع البيانات غير المرغوب فيها (المشار إليها غالبًا باسم GC) في الأساس؟
Browser Support
جمع البيانات المهملة
بشكل مبسط، فإن فكرة جمع البيانات غير المرغوب فيها هي محاولة استعادة الذاكرة التي خصصها البرنامج، ولكن لم يعُد يتم الرجوع إليها. ويُطلق على هذا النوع من الذاكرة اسم "البيانات غير المرغوب فيها". هناك العديد من الاستراتيجيات لتنفيذ عملية جمع البيانات غير المرغوب فيها. أحد هذه الأساليب هو احتساب المراجع، حيث يكون الهدف هو احتساب عدد المراجع إلى العناصر في الذاكرة. عندما لا تكون هناك أي مراجع إلى عنصر، يمكن وضع علامة عليه للإشارة إلى أنّه لم يعُد مستخدَمًا وبالتالي أصبح جاهزًا لجمع البيانات غير المرغوب فيها. يستخدم جامع البيانات غير الضرورية في 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)، ينفّذ المطوّر أيضًا برنامجًا خلفيًا للتجميع أثناء التنفيذ أو التجميع مسبقًا للبنية الجديدة. هذا الأسلوب منطقي جدًا لأنّه غالبًا ما يمكن إعادة تجميع الجزء الرئيسي من قاعدة الرموز لكل بنية جديدة.
نظرًا إلى أنّ Wasm منخفض المستوى، من الطبيعي تجربة الأسلوب نفسه: إعادة تجميع رمز الجهاز الافتراضي الرئيسي مع المحلّل اللغوي ودعم المكتبة وجمع البيانات غير الضرورية والمحسِّن إلى Wasm، وتنفيذ JIT أو AOT في الخلفية لـ Wasm إذا لزم الأمر. وقد أصبح ذلك ممكنًا منذ طرح الحد الأدنى من الميزات في Wasm، وهو يعمل بشكل جيد في العديد من الحالات. في الواقع، إنّ 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، عند نقل لغة برمجة إلى WebAssembly، لن يكون جامع البيانات غير المرغوب فيها الخاص بلغة البرمجة بحاجة إلى أن يكون جزءًا من عملية النقل، بل يمكن استخدام جامع البيانات غير المرغوب فيها الحالي.
للتحقّق من التأثير الفعلي لهذا التحسين، جمع فريق WebAssembly في 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 MVP
- WasmGC post-MVP
الإقرارات
تمت مراجعة هذه المقالة من قِبل ماتياس ليدتك وآدم كلاين وجوشوا بيل وألون زكاي وجاكوب كومرو وكليمنس باكس وإيمانويل زيغلر وراشيل أندرو.