เปิดใช้ WebAssembly Garbage Collection (WasmGC) ใน Chrome แล้วโดยค่าเริ่มต้น

ภาษาโปรแกรมมี 2 ประเภท ได้แก่ ภาษาโปรแกรมที่เก็บค่าขยะและภาษาโปรแกรมที่ต้องใช้การจัดการหน่วยความจำด้วยตนเอง ตัวอย่างของรูปแบบ URL ตัวอย่างข้างต้น ได้แก่ Kotlin, PHP หรือ Java กรณีหลังคือ C, C++ หรือ Rust ตามกฎทั่วไป ภาษาโปรแกรมในระดับที่สูงกว่ามีแนวโน้มที่จะมีการเก็บข้อมูลขยะเป็นฟีเจอร์มาตรฐานมากกว่า ในบล็อกโพสต์นี้ จุดมุ่งเน้นอยู่ที่ภาษาโปรแกรมที่เก็บขยะดังกล่าว และวิธีรวบรวมภาษาเหล่านั้นไปยัง WebAssembly (Wasm) แต่การเก็บข้อมูลขยะ (มักเรียกว่า GC) คืออะไร

การสนับสนุนเบราว์เซอร์

  • 119
  • 119
  • 120
  • x

บริการเก็บขยะ

กล่าวง่ายๆ ก็คือ แนวคิดเกี่ยวกับการเก็บขยะคือการพยายามเรียกคืนหน่วยความจำที่โปรแกรมจัดสรรไว้ แต่กลับไม่มีการอ้างอิงถึงอีกต่อไป หน่วยความจำเช่นนี้เรียกว่าขยะ การใช้ระบบเก็บขยะมีกลยุทธ์มากมาย หนึ่งในนั้นคือการนับการอ้างอิงที่วัตถุประสงค์คือการนับจำนวนการอ้างอิงไปยังออบเจ็กต์ในหน่วยความจำ เมื่อไม่มีการอ้างอิงไปยังออบเจ็กต์แล้ว ระบบอาจทำเครื่องหมายว่าไม่ใช้แล้วเพื่อให้พร้อมสำหรับการรวบรวมขยะ โปรแกรมเก็บขยะของ PHP ใช้การนับการอ้างอิง และการใช้ฟังก์ชัน xdebug_debug_zval() ของส่วนขยาย Xdebug จะช่วยให้คุณเห็นเบื้องหลังการทำงานของส่วนขยาย Xdebug ลองพิจารณาโปรแกรม PHP ต่อไปนี้

<?php
  $a= (string) rand();
  $c = $b = $a;
  $b = 42;
  unset($c);
  $a = null;
?>

โปรแกรมจะกำหนดตัวเลขสุ่มที่แคสต์เป็นสตริงไปยังตัวแปรใหม่ที่เรียกว่า a จากนั้นจึงสร้างตัวแปรใหม่ 2 รายการ ได้แก่ 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 สำหรับรันไทม์ของ Linux ในสภาพแวดล้อม Linux และยังหมายความว่ารันไทม์ของ PHP สามารถคอมไพล์สำหรับรันไทม์อื่นๆ ได้ด้วย ประมาณว่า Wasm ก็เป็นได้

วิธีดั้งเดิมในการย้ายภาษาไปยังรันไทม์ Wasm

สคริปต์ PHP จะได้รับการรวบรวมเป็นไบต์โค้ดเดียวกันและเรียกใช้โดย Zend Engine โดยอิสระจากแพลตฟอร์มที่ PHP ทำงานอยู่ Zend Engine เป็นสภาพแวดล้อมแบบคอมไพเลอร์และรันไทม์สำหรับภาษาสคริปต์ PHP ซึ่งประกอบด้วย Zend Virtual Machine (VM) ซึ่งประกอบด้วย Zend Compiler และ Zend Executor ภาษาอย่างภาษา PHP ที่ใช้งานในภาษาระดับสูงอื่นๆ เช่น C มักมีการเพิ่มประสิทธิภาพที่กำหนดเป้าหมายสถาปัตยกรรมเฉพาะ เช่น Intel หรือ ARM และต้องใช้แบ็กเอนด์ที่แตกต่างกันสำหรับแต่ละสถาปัตยกรรม ในบริบทนี้ Wasm แสดงถึงสถาปัตยกรรมใหม่ หาก VM มีโค้ดเฉพาะสถาปัตยกรรม เช่น การคอมไพล์แบบ Just-In-Time (JIT) หรือการคอมไพล์ล่วงหน้า (AOT) นักพัฒนาซอฟต์แวร์ก็จะใช้แบ็กเอนด์สำหรับ JIT/AOT สำหรับสถาปัตยกรรมใหม่ด้วย วิธีการนี้มีเหตุผลอย่างยิ่ง เพราะส่วนใหญ่แล้วฐานหลักของโค้ดมักจะถูกคอมไพล์ซ้ำสำหรับสถาปัตยกรรมใหม่แต่ละอย่างได้

เนื่องจาก Wasm มีระดับต่ำ ก็เป็นเรื่องปกติที่จะลองใช้วิธีการเดียวกันนี้ นั่นคือคอมไพล์โค้ด VM หลักอีกครั้งด้วยโปรแกรมแยกวิเคราะห์ การสนับสนุนไลบรารี การรวบรวมขยะ และตัวเพิ่มประสิทธิภาพให้กับ Wasm รวมถึงติดตั้งแบ็กเอนด์ JIT หรือ AOT สำหรับ Wasm หากจำเป็น เป็นไปได้ตั้งแต่ MVP ของ Wasm และวิธีนี้ได้ผลดีในหลายๆ กรณี ที่จริงแล้ว PHP ที่คอมไพล์ไปยัง Wasm คือสิ่งที่ขับเคลื่อน WordPress Playground ดูข้อมูลเพิ่มเติมเกี่ยวกับโปรเจ็กต์นี้ได้ในบทความสร้างประสบการณ์การใช้งาน WordPress ในเบราว์เซอร์ด้วย WordPress Playground และ WebAssembly

อย่างไรก็ตาม PHP Wasm จะทำงานในเบราว์เซอร์ในบริบทของ JavaScript ของภาษาโฮสต์ ใน Chrome JavaScript และ 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 แต่ละรายการมีประเภทและโครงสร้างคงที่ ซึ่งช่วยให้ VM สร้างโค้ดที่มีประสิทธิภาพเพื่อเข้าถึงช่องของตนได้อย่างง่ายดาย โดยไม่ต้องเสี่ยงที่การเพิ่มประสิทธิภาพเหมือนกับภาษาแบบไดนามิกอย่าง JavaScript ข้อเสนอนี้เพิ่มการสนับสนุนที่มีประสิทธิภาพสำหรับภาษาที่มีการจัดการระดับสูงไปยัง WebAssembly ผ่านประเภทฮีปของโครงสร้างและอาร์เรย์ที่ทำให้คอมไพเลอร์ภาษาที่กำหนดเป้าหมายเป็น Wasm สามารถผสานรวมกับเครื่องมือเก็บขยะใน VM ของโฮสต์ พูดง่ายๆ ก็คือ สำหรับ WasmGC การย้ายภาษาโปรแกรมไปยัง Wasm หมายความว่าโปรแกรมเก็บขยะของภาษาโปรแกรมจะไม่ต้องเป็นส่วนหนึ่งของพอร์ตอีกต่อไป แต่สามารถใช้งานเครื่องมือเก็บขยะที่มีอยู่แล้วแทนได้

เพื่อยืนยันผลกระทบในชีวิตจริงของการปรับปรุงครั้งนี้ ทีม Wasm ของ Chrome ได้รวบรวมการเปรียบเทียบ Fannkuch (ซึ่งจัดสรรโครงสร้างข้อมูลตามการทำงาน) จาก C, Rust และ Java ไบนารี C และ Rust อาจอยู่ที่ใดก็ได้ตั้งแต่ 6.1 K ถึง 9.6 K โดยขึ้นอยู่กับแฟล็กคอมไพเลอร์ต่างๆ ในขณะที่เวอร์ชัน Java จะเล็กกว่ามากที่ 2.3 K C และ Rust ไม่ได้รวมเครื่องมือเก็บขยะ แต่ยังคงรวม malloc/free เพื่อจัดการหน่วยความจำ เหตุผลที่ Java มีขนาดเล็กกว่านี้เพราะไม่จำเป็นต้องรวมโค้ดการจัดการหน่วยความจำใดๆ เลย นี่เป็นเพียงตัวอย่างหนึ่ง แต่แสดงให้เห็นว่าไบนารี WasmGC มีศักยภาพที่จะมีขนาดเล็กมาก และนี่ยังเป็นก่อนที่จะมีการพัฒนาที่สำคัญในการเพิ่มประสิทธิภาพขนาด

การดูภาษาโปรแกรมที่มีพอร์ต WasmGC ในการทำงาน

คอตลิน แวสเอ็ม

หนึ่งในภาษาโปรแกรมแรกๆ ที่ย้ายไปยัง 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 API ที่แปลงเป็น Kotlin เมื่อใช้ร่วมกับ Compose Multiplatform ซึ่งจะช่วยให้นักพัฒนาแอปสร้าง UI ที่อาจสร้างขึ้นสำหรับแอป Android Kotlin ไว้แล้วได้ ทั้งนี้จะเหมาะสมยิ่งขึ้น ลองดูการสำรวจก่อนหน้านี้เกี่ยวกับเรื่องนี้ด้วยการสาธิตโปรแกรมดูรูปภาพ Kotlin/Wasm และสำรวจซอร์สโค้ด ตัวอย่างเช่น ได้รับความเอื้อเฟื้อจากทีม Kotlin ด้วย

Dart และ Flutter

ทีม Dart และ Flutter ของ Google กำลังเตรียมการสนับสนุนสำหรับ WasmGC ด้วย งานคอมไพล์ Dart-to-Wasm ใกล้เสร็จสมบูรณ์แล้ว และทีมงานกำลังดำเนินการสนับสนุนการใช้เครื่องมือสำหรับการให้บริการเว็บแอปพลิเคชัน Flutter ที่คอมไพล์ให้กับ WebAssembly อ่านสถานะปัจจุบันของงานได้ในเอกสาร Flutter การสาธิตต่อไปนี้คือตัวอย่าง Flutter WasmGC

ดูข้อมูลเพิ่มเติมเกี่ยวกับ WasmGC

บล็อกโพสต์นี้แทบไม่มีรอยขีดข่วนเลย และส่วนใหญ่จะให้ภาพรวมระดับสูงของ WasmGC ดูข้อมูลเพิ่มเติมเกี่ยวกับฟีเจอร์นี้ได้ที่ลิงก์ต่อไปนี้

ข้อความแสดงการยอมรับ

รูปภาพหลักโดย Gary Chan ใน Unsplash บทความนี้เขียนโดย Matthias Liedtke, Adam Klein, Joshua Bell, Alon Zakai, Jakob Kummerow, Clemens Backes, Emanuel Ziegler และ Rachel Andrew