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

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

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

  • Chrome: 119.
  • एज: 119.
  • Firefox: 120.
  • Safari: यह सुविधा काम नहीं करती.

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

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

Wasm का लेवल बहुत कम है. इसलिए, यहां इसी तरीके को आज़माया जा सकता है: मुख्य वीएम कोड को इसके पार्सर, लाइब्रेरी से जुड़ी सहायता, गै़रबेज कलेक्शन, और Wasm के लिए ऑप्टिमाइज़र की मदद से फिर से कंपाइल करें. साथ ही, ज़रूरत होने पर, Wasm के लिए JIT या AOT बैकएंड लागू करें. Wasm एमवीपी के बाद से, यह सुविधा उपलब्ध है. यह कई मामलों में अच्छी तरह से काम करती है. असल में, 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 मॉड्यूल को, पहले से मौजूद जीसी का फिर से इस्तेमाल करने की अनुमति देने से, इन समस्याओं से बचा जा सकता है.

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

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

इस सुधार के असर की पुष्टि करने के लिए, Chrome की Wasm टीम ने C, Rust, और Java से Fannkuch बेंचमार्क (जो काम करते समय डेटा स्ट्रक्चर को असाइन करता है) के वर्शन को कॉम्पाइल किया है. अलग-अलग कंपाइलर फ़्लैग के आधार पर C और रस्ट बाइनरी, 6.1 K से 9.6 K तक हो सकती हैं, जबकि Java का वर्शन सिर्फ़ 2.3 K पर काफ़ी छोटा होता है! 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 कोड में बुनियादी तौर पर, Kotlin की मदद से बदले गए JavaScript ओएम एपीआई शामिल हैं. Compose Multiplatform के साथ इस्तेमाल करने पर, यह सुविधा ज़्यादा काम की हो जाती है. इससे डेवलपर, उस यूज़र इंटरफ़ेस (यूआई) को बेहतर बना सकते हैं जिसे उन्होंने अपने Android Kotlin ऐप्लिकेशन के लिए पहले से बनाया हो. Kotlin/Wasm इमेज व्यूअर के डेमो की मदद से, इसकी शुरुआती जानकारी देखें. साथ ही, Kotlin टीम की मदद से, इसके सोर्स कोड को भी एक्सप्लोर करें.

Dart और Flutter

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

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

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

धन्यवाद

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