WebAssembly Garbage Collection (WasmGC) اکنون به طور پیش فرض در Chrome فعال شده است

دو نوع زبان برنامه نویسی وجود دارد: زبان های برنامه نویسی جمع آوری شده زباله و زبان های برنامه نویسی که نیاز به مدیریت دستی حافظه دارند. نمونه های قبلی، در میان بسیاری دیگر، کاتلین، پی اچ پی یا جاوا هستند. نمونه هایی از دومی C، C++ یا Rust هستند. به عنوان یک قاعده کلی، زبان های برنامه نویسی سطح بالاتر به احتمال زیاد دارای جمع آوری زباله به عنوان یک ویژگی استاندارد هستند. در این پست وبلاگ، تمرکز بر روی چنین زبان های برنامه نویسی جمع آوری شده و نحوه کامپایل آنها در WebAssembly (Wasm) است. اما جمع آوری زباله (که اغلب به عنوان GC شناخته می شود) برای شروع چیست؟

پشتیبانی مرورگر

  • کروم: 119.
  • لبه: 119.
  • فایرفاکس: 120.
  • سافاری: 18.2.

جمع آوری زباله

به عبارت ساده تر، ایده جمع آوری زباله تلاش برای بازیابی حافظه ای است که توسط برنامه تخصیص داده شده است، اما دیگر به آن اشاره نمی شود. به چنین خاطره ای زباله می گویند. راهکارهای زیادی برای اجرای جمع آوری زباله وجود دارد. یکی از آنها شمارش مرجع است که در آن هدف شمارش تعداد ارجاعات به اشیاء در حافظه است. هنگامی که دیگر ارجاعی به یک شی وجود ندارد، می توان آن را به عنوان دیگر مورد استفاده قرار نگرفت و در نتیجه برای جمع آوری زباله علامت گذاری کرد. جمع‌آوری زباله 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 را از کد منبع بسازند . برای مثال، در یک محیط لینوکس، مراحل ./buildconf && ./configure && make PHP را برای زمان اجرا لینوکس می‌سازد. اما این همچنین به این معنی است که زمان اجرا PHP را می توان برای زمان های اجرا دیگری کامپایل کرد، مانند، حدس زدید، Wasm.

روش‌های سنتی انتقال زبان‌ها به زمان اجرا Wasm

مستقل از پلتفرمی که PHP روی آن اجرا می شود، اسکریپت های PHP در همان بایت کد کامپایل شده و توسط موتور Zend اجرا می شوند. Zend Engine یک محیط کامپایلر و زمان اجرا برای زبان برنامه نویسی PHP است. این ماشین مجازی از Zend Virtual Machine (VM) تشکیل شده است که از کامپایلر Zend و Zend Executor تشکیل شده است. زبان‌هایی مانند PHP که در سایر زبان‌های سطح بالا مانند C پیاده‌سازی می‌شوند، معمولاً دارای بهینه‌سازی‌هایی هستند که معماری‌های خاصی مانند Intel یا ARM را هدف قرار می‌دهند و برای هر معماری به یک Backend متفاوت نیاز دارند. در این زمینه Wasm نمایانگر معماری جدیدی است. اگر VM دارای کد خاص معماری باشد، مانند کامپایل در زمان (JIT) یا پیش از زمان (AOT)، توسعه دهنده همچنین یک Backend برای JIT/AOT برای معماری جدید پیاده سازی می کند. این رویکرد بسیار منطقی است زیرا اغلب بخش اصلی پایگاه کد را می توان برای هر معماری جدید دوباره کامپایل کرد.

با توجه به سطح پایین Wasm، طبیعی است که همین رویکرد را در آنجا امتحان کنید: کد VM اصلی را با تجزیه‌کننده، پشتیبانی کتابخانه، جمع‌آوری زباله و بهینه‌ساز آن در Wasm مجددا کامپایل کنید و در صورت نیاز یک JIT یا AOT Backend برای Wasm پیاده‌سازی کنید. این امر از زمان Wasm MVP امکان پذیر بوده است و در بسیاری از موارد در عمل به خوبی عمل می کند. در واقع، PHP کامپایل شده در Wasm همان چیزی است که زمین بازی وردپرس را تقویت می کند. در مقاله ایجاد تجربیات وردپرس درون مرورگر با وردپرس Playground و WebAssembly درباره پروژه بیشتر بیاموزید.

با این حال، PHP Wasm در مرورگر در زمینه زبان میزبان جاوا اسکریپت اجرا می شود. در Chrome، جاوا اسکریپت و Wasm در V8 ، موتور جاوا اسکریپت منبع باز Google که ECMAScript را همانطور که در ECMA-262 مشخص شده است، اجرا می‌کند. و V8 در حال حاضر یک زباله جمع کن دارد . این بدان معناست که توسعه‌دهندگانی که از مثلاً PHP کامپایل شده در Wasm استفاده می‌کنند، یک پیاده‌سازی جمع‌آوری زباله از زبان انتقال‌یافته (PHP) را به مرورگری ارسال می‌کنند که قبلاً جمع‌آوری زباله دارد، که به همان اندازه که به نظر می‌رسد ضایع‌کننده است. اینجاست که WasmGC وارد می شود.

مشکل دیگر رویکرد قدیمی که به ماژول‌های Wasm اجازه می‌داد تا GC خود را بر روی حافظه خطی Wasm بسازند این است که هیچ تعاملی بین زباله‌گیر خود Wasm و زباله‌گیر داخلی در زبان کامپایل‌شده به Wasm وجود ندارد. که منجر به مشکلاتی مانند نشت حافظه و تلاش های ناکارآمد برای جمع آوری می شود. اجازه دادن به ماژول‌های Wasm برای استفاده مجدد از GC داخلی موجود، از این مشکلات جلوگیری می‌کند.

انتقال زبان های برنامه نویسی به زمان های اجرا جدید با WasmGC

WasmGC پیشنهادی از گروه انجمن WebAssembly است. پیاده‌سازی Wasm MVP کنونی فقط می‌تواند با اعداد، یعنی اعداد صحیح و شناور، در حافظه خطی سروکار داشته باشد، و با ارسال پیشنهاد انواع مرجع ، Wasm می‌تواند به منابع خارجی نیز بچسبد. WasmGC اکنون انواع ساختار و آرایه هیپ را اضافه می کند که به معنای پشتیبانی از تخصیص حافظه غیر خطی است. هر شی WasmGC دارای یک نوع و ساختار ثابت است، که باعث می‌شود ماشین‌های مجازی به راحتی کدهای کارآمد را برای دسترسی به فیلدهای خود بدون خطر بهینه‌سازی‌های غیربهینه‌سازی که زبان‌های پویا مانند جاوا اسکریپت دارند، تولید کنند. بنابراین، این پیشنهاد، پشتیبانی کارآمدی را از زبان‌های مدیریت شده سطح بالا به WebAssembly، از طریق انواع هیپ ساختار و آرایه اضافه می‌کند که کامپایلرهای زبانی را که Wasm را هدف قرار می‌دهند، قادر می‌سازد تا با جمع‌آوری زباله در VM میزبان ادغام شوند. به عبارت ساده شده، این بدان معناست که با WasmGC، پورت کردن یک زبان برنامه نویسی به Wasm به این معنی است که زباله جمع کننده زبان برنامه نویسی دیگر نیازی به بخشی از پورت ندارد، اما در عوض می توان از زباله جمع کن موجود استفاده کرد.

برای تأیید تأثیر واقعی این بهبود، تیم Wasm Chrome نسخه‌هایی از معیار Fannkuch (که ساختارهای داده را همانطور که کار می‌کند تخصیص می‌دهد) از C ، Rust و Java گردآوری کرده است. باینری های C و Rust بسته به پرچم های مختلف کامپایلر می توانند از 6.1 K تا 9.6 K باشند، در حالی که نسخه جاوا بسیار کوچکتر است و تنها 2.3 K است! C و Rust شامل جمع‌آوری زباله نیستند، اما همچنان malloc/free برای مدیریت حافظه باندل می‌کنند، و دلیل کوچک‌تر شدن جاوا در اینجا این است که اصلاً نیازی به بسته‌بندی کد مدیریت حافظه ندارد. این فقط یک مثال خاص است، اما نشان می‌دهد که باینری‌های WasmGC پتانسیل کوچک بودن را دارند، و این حتی قبل از هر کار مهمی برای بهینه‌سازی اندازه است.

مشاهده یک زبان برنامه نویسی با پورت WasmGC در عمل

کاتلین واسم

یکی از اولین زبان های برنامه نویسی که به لطف 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 در بالا اساساً شامل APIهای JavaScript OM تبدیل شده به Kotlin است . در ترکیب با Compose Multiplatform که به توسعه دهندگان اجازه می دهد تا بر اساس رابط کاربری که ممکن است قبلاً برای برنامه های Android Kotlin خود ایجاد کرده اند، منطقی تر شود. یک کاوش اولیه در این مورد را با نسخه ی نمایشی نمایشگر تصویر Kotlin/Wasm بررسی کنید و کد منبع آن را کشف کنید، به همین ترتیب توسط تیم Kotlin.

دارت و فلاتر

تیم Dart و Flutter در گوگل نیز در حال آماده سازی پشتیبانی برای WasmGC هستند. کار کامپایل Dart-to-Wasm تقریباً کامل شده است و تیم در حال کار بر روی پشتیبانی ابزاری برای ارائه برنامه های وب Flutter کامپایل شده در WebAssembly هستند. شما می توانید در مورد وضعیت فعلی کار در مستندات فلاتر مطالعه کنید. نسخه ی نمایشی زیر پیش نمایش Flutter WasmGC است.

درباره WasmGC بیشتر بدانید

این پست وبلاگ به سختی سطح را خراشیده است و بیشتر نمای کلی سطح بالایی از WasmGC را ارائه می دهد. برای کسب اطلاعات بیشتر در مورد این ویژگی، این لینک ها را بررسی کنید:

قدردانی

این مقاله توسط Matthias Liedtke ، Adam Klein ، Joshua Bell ، Alon Zakai ، Jakob Kummerow ، Clemens Backes ، Emanuel Ziegler و Rachel Andrew بررسی شده است.