WebAssembly गार्बेज कलेक्शन (WasmGC) को अब Chrome में डिफ़ॉल्ट रूप से चालू कर दिया गया है

प्रोग्रामिंग लैंग्वेज दो तरह की होती हैं: ग़ैर-ज़रूरी डेटा को इकट्ठा करने वाली प्रोग्रामिंग लैंग्वेज और ऐसी प्रोग्रामिंग लैंग्वेज जिनमें मैन्युअल रूप से मेमोरी मैनेजमेंट की ज़रूरत होती है. Kotlin, PHP या Java, इनमें से कोई भी भाषा, पहले कैटगरी में आती है. C, C++, या Rust, इसके उदाहरण हैं. आम तौर पर, हाई-लेवल प्रोग्रामिंग भाषाओं में, स्टैंडर्ड सुविधा के तौर पर, ग़ैर-ज़रूरी डेटा हटाने की सुविधा होती है. इस ब्लॉग पोस्ट में, ऐसी ग़ैर-ज़रूरी चीज़ों को हटाने वाली प्रोग्रामिंग भाषाओं पर फ़ोकस किया गया है. साथ ही, यह भी बताया गया है कि इन्हें WebAssembly (Wasm) में कैसे कंपाइल किया जा सकता है. लेकिन सबसे पहले, गै़रबेज कलेक्शन (जिसे अक्सर जीसी कहा जाता है) क्या है?

ब्राउज़र के इस्तेमाल से जुड़ी सहायता

  • Chrome: 119.
  • Edge: 119.
  • Firefox: 120.
  • Safari: 18.2.

कचरा हटाने की सेवा

आसान शब्दों में, गै़रबेज कलेक्शन का मतलब है कि प्रोग्राम के लिए जो मेमोरी ऐलोकेट की गई थी उसे वापस पाना. हालांकि, अब इसका इस्तेमाल नहीं किया जा रहा है. ऐसी मेमोरी को ग़ैर-ज़रूरी मेमोरी कहा जाता है. गै़रबेज कलेक्शन को लागू करने के कई तरीके हैं. इनमें से एक रेफ़रंस काउंटिंग है. इसका मकसद, मेमोरी में मौजूद ऑब्जेक्ट के रेफ़रंस की संख्या की गिनती करना है. जब किसी ऑब्जेक्ट का कोई रेफ़रंस नहीं होता है, तो उसे 'अब इस्तेमाल नहीं किया जा रहा है' के तौर पर मार्क किया जा सकता है. इसके बाद, उसे गै़रबेज कलेक्शन के लिए तैयार किया जा सकता है. PHP का कचरा कलेक्टर, रेफ़रंस काउंटिंग का इस्तेमाल करता है. साथ ही, Xdebug एक्सटेंशन के xdebug_debug_zval() फ़ंक्शन का इस्तेमाल करके, इसकी परफ़ॉर्मेंस के बारे में जानकारी पाई जा सकती है. यहां दिया गया 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 में लागू किया जाता है. GitHub पर PHP का सोर्स कोड देखा जा सकता है. PHP का गार्बेज कलेक्शन कोड, मुख्य रूप से zend_gc.c फ़ाइल में मौजूद होता है. ज़्यादातर डेवलपर, अपने ऑपरेटिंग सिस्टम के पैकेज मैनेजर की मदद से PHP इंस्टॉल करेंगे. हालांकि, डेवलपर सोर्स कोड से PHP भी बना सकते हैं. उदाहरण के लिए, Linux एनवायरमेंट में, ./buildconf && ./configure && make चरण, Linux रनटाइम के लिए PHP बनाएंगे. हालांकि, इसका मतलब यह भी है कि PHP रनटाइम को अन्य रनटाइम के लिए कंपाइल किया जा सकता है. जैसे, Wasm.

भाषाओं को Wasm रनटाइम पर पोर्ट करने के पारंपरिक तरीके

PHP स्क्रिप्ट को एक ही बाइटकोड में कंपाइल किया जाता है और Zend Engine से चलाया जाता है. भले ही, PHP किसी भी प्लैटफ़ॉर्म पर चल रहा हो. Zend Engine, PHP स्क्रिप्टिंग भाषा के लिए एक कंपाइलर और रनटाइम एनवायरमेंट है. इसमें Zend वर्चुअल मशीन (VM) शामिल है, जो Zend कंपाइलर और Zend एक्ज़ीक्यूटर से बनी है. PHP जैसी भाषाओं को C जैसी अन्य हाई-लेवल भाषाओं में लागू किया जाता है. आम तौर पर, इनमें ऐसे ऑप्टिमाइज़ेशन होते हैं जो Intel या ARM जैसे खास आर्किटेक्चर को टारगेट करते हैं. साथ ही, हर आर्किटेक्चर के लिए अलग-अलग बैकएंड की ज़रूरत होती है. इस संदर्भ में, Wasm एक नए आर्किटेक्चर को दिखाता है. अगर वीएम में आर्किटेक्चर के हिसाब से कोड है, जैसे कि जस्ट-इन-टाइम (JIT) या पहले से (AOT) कंपाइलेशन, तो डेवलपर नए आर्किटेक्चर के लिए JIT/AOT के लिए बैकएंड भी लागू करता है. यह तरीका काफ़ी सही है, क्योंकि अक्सर हर नए आर्किटेक्चर के लिए, कोडबेस के मुख्य हिस्से को फिर से कंपाइल किया जा सकता है.

Wasm का लेवल बहुत कम है. इसलिए, उसमें भी यही तरीका आज़माया जा सकता है: मुख्य VM कोड को उसके पार्स करने वाले टूल, लाइब्रेरी के साथ काम करने की सुविधा, ग़ैर-ज़रूरी डेटा हटाने की सुविधा, और ऑप्टिमाइज़र के साथ Wasm में फिर से कंपाइल करें. साथ ही, ज़रूरत पड़ने पर Wasm के लिए JIT या AOT बैकएंड लागू करें. Wasm MVP के बाद से, यह काम करना शुरू हो गया है. यह कई मामलों में सही तरीके से काम करता है. असल में, WordPress Playground को Wasm में कंपाइल किए गए PHP की मदद से चलाया जाता है. इस प्रोजेक्ट के बारे में ज़्यादा जानने के लिए, WordPress Playground और WebAssembly की मदद से, ब्राउज़र में WordPress का अनुभव पाएं लेख पढ़ें.

हालांकि, PHP Wasm, ब्राउज़र में होस्ट भाषा JavaScript के संदर्भ में चलता है. Chrome में, JavaScript और Wasm को V8 में चलाया जाता है. यह Google का ओपन सोर्स JavaScript इंजन है, जो ECMA-262 में बताए गए तरीके के मुताबिक ECMAScript को लागू करता है. साथ ही, V8 में पहले से ही एक कचरा कलेक्टर मौजूद है. इसका मतलब है कि डेवलपर, Wasm में कंपाइल की गई PHP का इस्तेमाल करते हैं. इस वजह से, वे ब्राउज़र में पोर्ट की गई भाषा (PHP) के लिए, गैर-ज़रूरी डेटा हटाने वाले टूल को शिप करते हैं. हालांकि, ब्राउज़र में पहले से ही गैर-ज़रूरी डेटा हटाने वाला टूल मौजूद होता है. ऐसे में, WasmGC की मदद ली जा सकती है.

Wasm मॉड्यूल को Wasm की लीनियर मेमोरी के ऊपर अपना जीसी बनाने की अनुमति देने के पुराने तरीके की एक और समस्या यह है कि Wasm के अपने कचरा कलेक्टर और Wasm में कंपाइल की गई भाषा के ऊपर बने कचरा कलेक्टर के बीच कोई इंटरैक्शन नहीं होता. इस वजह से, मेमोरी लीक और कचरा इकट्ठा करने में लगने वाले समय में बढ़ोतरी जैसी समस्याएं आती हैं. Wasm मॉड्यूल को, पहले से मौजूद जीसी का फिर से इस्तेमाल करने की अनुमति देने से, इन समस्याओं से बचा जा सकता है.

WasmGC की मदद से, प्रोग्रामिंग भाषाओं को नए रनटाइम पर पोर्ट करना

WasmGC, WebAssembly कम्यूनिटी ग्रुप का प्रस्ताव है. फ़िलहाल, Wasm एमवीपी को लागू करने पर, लीनियर मेमोरी में सिर्फ़ संख्याओं, यानी कि पूर्णांक और फ़्लोट का इस्तेमाल किया जा सकता है. हालांकि, रेफ़रंस टाइप के प्रस्ताव को शिप करने के बाद, Wasm में बाहरी रेफ़रंस भी इस्तेमाल किए जा सकेंगे. WasmGC में अब स्ट्रक्चर और ऐरे ढेर टाइप जोड़े गए हैं. इसका मतलब है कि नॉन-लीनियर मेमोरी ऐलोकेशन के लिए सहायता मिलती है. हर WasmGC ऑब्जेक्ट का टाइप और स्ट्रक्चर तय होता है. इसकी वजह से, VM अपने फ़ील्ड को ऐक्सेस करने के लिए बेहतर कोड जनरेट कर पाते हैं. साथ ही, उन्हें JavaScript जैसी डाइनैमिक भाषाओं में होने वाले deoptimizations के जोखिम से भी बचा जा सकता है. इस प्रस्ताव के तहत, WebAssembly में बेहतर तरीके से मैनेज की जाने वाली हाई-लेवल भाषाओं के लिए बेहतर सहायता जोड़ी गई है. इसके लिए, स्ट्रक्चर और ऐरे हीप टाइप का इस्तेमाल किया गया है. इनकी मदद से, Wasm को टारगेट करने वाले भाषा कंपाइलर, होस्ट VM में मौजूद कचरा इकट्ठा करने वाले टूल के साथ इंटिग्रेट हो पाते हैं. आसान शब्दों में, इसका मतलब है कि WasmGC की मदद से, किसी प्रोग्रामिंग भाषा को Wasm में पोर्ट करने का मतलब है कि प्रोग्रामिंग भाषा के कचरा कलेक्टर को अब पोर्ट का हिस्सा नहीं होना चाहिए. इसके बजाय, मौजूदा कचरा कलेक्टर का इस्तेमाल किया जा सकता है.

इस सुधार के असर की पुष्टि करने के लिए, Chrome की Wasm टीम ने C, Rust, और Java से Fannkuch बेंचमार्क (जो काम करते समय डेटा स्ट्रक्चर को असाइन करता है) के वर्शन को कॉम्पाइल किया है. अलग-अलग कंपाइलर फ़्लैग के आधार पर, C और Rust बाइनरी का साइज़ 6.1 के से 9.6 के के बीच हो सकता है. वहीं, Java वर्शन का साइज़ बहुत छोटा है, जो सिर्फ़ 2.3 के है! C और Rust में, गै़रबेज कलेक्टर शामिल नहीं होता. हालांकि, वे मेमोरी मैनेज करने के लिए malloc/free को बंडल करते हैं. Java का साइज़ यहां इसलिए छोटा है, क्योंकि उसे मेमोरी मैनेज करने वाले किसी भी कोड को बंडल करने की ज़रूरत नहीं होती. यह सिर्फ़ एक उदाहरण है, लेकिन इससे पता चलता है कि WasmGC बाइनरी का साइज़ बहुत छोटा हो सकता है. यह साइज़, साइज़ को ऑप्टिमाइज़ करने से पहले का है.

WasmGC पर पोर्ट की गई प्रोग्रामिंग भाषा को इस्तेमाल करते हुए देखना

Kotlin Wasm

WasmGC की मदद से, Wasm में पोर्ट की गई पहली प्रोग्रामिंग लैंग्वेज में से एक है 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 API को Kotlin में बदला गया है. Compose Multiplatform के साथ इस्तेमाल करने पर, यह सुविधा ज़्यादा काम की हो जाती है. इससे डेवलपर, अपने Android Kotlin ऐप्लिकेशन के लिए पहले से बनाए गए यूज़र इंटरफ़ेस (यूआई) पर आधारित यूआई बना सकते हैं. Kotlin/Wasm इमेज व्यूअर के डेमो की मदद से, इसकी शुरुआती जानकारी देखें. साथ ही, Kotlin टीम की मदद से, इसके सोर्स कोड को भी एक्सप्लोर करें.

Dart और Flutter

Google की Dart और Flutter टीमें भी WasmGC के लिए सहायता तैयार कर रही हैं. Dart को Wasm में कंपाइल करने का काम लगभग पूरा हो चुका है. अब टीम, WebAssembly में कंपाइल किए गए Flutter वेब ऐप्लिकेशन को डिलीवर करने के लिए, टूल की सहायता पर काम कर रही है. Flutter के दस्तावेज़ में, इस काम की मौजूदा स्थिति के बारे में पढ़ा जा सकता है. यहां दिया गया डेमो, Flutter WasmGC की झलक है.

WasmGC के बारे में ज़्यादा जानें

इस ब्लॉग पोस्ट में, WasmGC के बारे में सिर्फ़ खास जानकारी दी गई है. इस सुविधा के बारे में ज़्यादा जानने के लिए, ये लिंक देखें:

आभार

इस लेख की समीक्षा मैथियास लीडके, आदम क्लेन, जोशुआ बेल, अलोन ज़काई, जैकब कुम्मेरो, क्लेमेंस बैकिस, एमानुएल ज़िगलर, और रेचल एंड्रयू ने की है.