พื้นฐาน Memory
module WebAssembly สามารถประกาศ byte block ดิบที่เรียกว่า linear memory ซึ่งต่างจาก JavaScript heap โดย memory นี้เป็น flat, untyped array ของ byte ที่ทั้ง module Wasm และ JavaScript สามารถอ่านและเขียนได้โดยตรง เป็นกลไกหลักในการส่งข้อมูลที่ซับซ้อน — string, array, struct — ระหว่าง WebAssembly และ host
การประกาศ memory ด้วย (memory N)
หัวข้อที่มีชื่อว่า “การประกาศ memory ด้วย (memory N)”การประกาศ (memory N) จอง N หน้า ของ memory โดยแต่ละหน้ามีขนาดพอดี 64 KiB (65 536 byte) ขนาดขั้นต่ำที่มีประโยชน์คือหนึ่งหน้า:
(memory 1)นี่จะให้ module ของคุณมี byte ที่ addressable ได้ 65 536 byte ทั้งหมดถูก initialise เป็น zero ตอน instantiation
การโหลดและจัดเก็บ integer
หัวข้อที่มีชื่อว่า “การโหลดและจัดเก็บ integer”WebAssembly มีคำสั่ง load และ store แบบ typed สำหรับอ่านและเขียนค่าที่ byte address เฉพาะเจาะจง
i32.store— pop address และ 32-bit integer จาก stack เขียน 4 byte ที่ address นั้นi32.load— pop address จาก stack อ่าน 4 byte และ push ผลลัพธ์i32
คำสั่งทั้งสองรองรับ attribute offset แบบ static ที่ถูกบวกเข้ากับ runtime address ซึ่งมีประโยชน์สำหรับการเข้าถึง field ภายใน struct
การ Export memory ไปยัง JavaScript
หัวข้อที่มีชื่อว่า “การ Export memory ไปยัง JavaScript”JavaScript ไม่สามารถเข้าถึง Wasm memory ได้จนกว่า module จะ export memory ออกมา ใช้ inline export syntax:
(memory (export "mem") 1)ฝั่ง JavaScript ยังสามารถสร้าง WebAssembly.Memory object และส่งเป็น import ได้:
const memory = new WebAssembly.Memory({ initial: 1 });ตัวอย่างการ Store และ Load
หัวข้อที่มีชื่อว่า “ตัวอย่างการ Store และ Load”นี่คือ module ที่สมบูรณ์ที่เก็บค่า i32 ที่ byte address 100 และโหลดกลับทันที:
(module (memory (export "mem") 1) (func (export "storeAndLoad") (param $val i32) (result i32) i32.const 100 ;; address local.get $val ;; value to store i32.store i32.const 100 ;; address i32.load)) ;; load backRunner ด้านล่างเก็บ 999 ที่ offset 100 อ่านกลับมา และอ่าน mem[0] ด้วย (ซึ่งควรเป็น 0 เนื่องจากไม่มีอะไรเขียนที่นั่น)
ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ข้อแลกเปลี่ยน”| ตัวเลือก | Benefit | Cost |
|---|---|---|
TypedArray view ทับ mem.buffer โดยตรง | อ่าน/เขียน byte แบบ zero-copy รวดเร็ว ไม่ต้อง allocate เพิ่ม | ต้องสร้าง view ใหม่ทุกครั้งที่ memory ถูก grow ไม่งั้น view เก่าจะชี้ไปยัง buffer ที่ detach ไปแล้ว |
| จัดการ layout ของ memory เอง (คำนวณ address ด้วยมือ) | ควบคุม memory ได้เต็มที่ ไม่มี overhead จาก runtime | ไม่มี garbage collector หรือ bounds-checking แบบ JavaScript คอยช่วย ต้องดูแล lifetime ของข้อมูลเอง |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”- เขียนที่ address เกินขอบเขตของ page ที่จองไว้ (เช่น จอง
(memory 1)แต่ store ที่ offset เกิน 65 536) ทำให้เกิด trap เพราะ WebAssembly ไม่มี garbage collector หรือ bounds-checking layer ให้แบบ JavaScript - ลืมว่า
(memory N)ขยายได้ทีละทั้ง page (64 KiB) เท่านั้น จะจองแค่บางไบต์ไม่ได้ ทำให้เผลอ allocate เกินความจำเป็น - ลืม export memory ด้วย
(memory (export "mem") 1)แล้วสงสัยว่าทำไม JavaScript เข้าถึงinstance.exports.memไม่ได้
💡 ตัวอย่างจากของจริง
เครื่องมือแก้ไขภาพใน browser สไตล์ Squoosh ใช้ linear memory เก็บ raw pixel buffer โดยตรง แทนที่จะ copy ข้อมูลภาพไปมาระหว่าง JavaScript กับ Wasm ทุกครั้งที่ประมวลผล ทำให้ resize หรือ compress ภาพขนาดใหญ่ได้เร็วขึ้นมาก