JS-104 อยากรู้มั้ย Garbage Collection ทำงานยังไงใน JavaScript
กาลครั้งหนึ่งนานมาแล้ว… สมัยจบใหม่ไฟเกือบร้อนแรง เดินทางไปสมัครงาน ณ บริษัทสายเทคโนโลยีชื่อดังที่แห่งหนึ่ง ผู้สัมภาษณ์ถามผมว่า Garbage Collection ใน C# ทำงานยังไง… ซึ่งจริงๆ ผมเข้าใจว่ามันเป็นตัวเคลีย memory ที่ไม่ได้ใช้แล้ว และเคยใช้คำสั่งแบบ manual เองอยู่บ้าง แต่ ณ ตอนนั้นยังไม่ค่อยเข้าใจ context ของคำถามว่าเขาอยากจะรู้อะไร ก็เลยตอบไปว่าไม่รู้… ผลการสัมภาษณ์ก็เป็นไปตามคาดว่าไม่ผ่าน ผมก็ไม่ได้ติดใจอะไร
ผ่านมาประมาณ 2 ปีเมื่อประสบการณ์เริ่มแกร่งกล้า ผมไปสมัครที่เดิมอีกครั้ง ก็โดนคำถามเดิมซึ่งก็ไม่คิดว่าจะโดนถามอีก แต่ก็ตอบไม่ได้เหมือนเดิม เมื่อถึงตอนแจ้งผลสรุปว่า… “ไม่ผ่าน” เพราะคำถามที่เคยถามเมื่อสองปีที่แล้วยังตอบไม่ได้ !!
แล้วจะมาเล่าทำมะเขืออะไร ก็ไม่มีอะไรมากครับ อะไรที่เป็นความรู้แบบ Fundamental ส่วนใหญ่มักมีประโยชน์ไม่ทางใดก็ทางหนึ่ง ก็อยากให้ทุกๆคน ศึกษาเรียนรู้กันไว้ เผื่อนำไปปรับใช้ได้ในอนาคตครับผม
Garbage Collection
ไม่ว่าในภาษา Programming ภาษาใดๆ ก็มักจะมี Garbage Collector อยู่เสมอมันเป็นตัวช่วยจัดการ memory ที่เป็นขยะ หรือไม่ถูกใช้ เพราะในทุกๆบรรทัดของ code ที่เราเขียนจะต้องถูก allocate ลงใน memory เพื่อทำงาน เช่น การประกาศตัวแปร ประกาศฟังก์ชั่น บลาๆ ซึ่งมันก็มีโอกาสที่ตัวแปรถูกใช้ครั้งเดียว และมันยังค้างอยู่ใน memory นั่นทำให้ Garbage Collecter มาช่วยจัดการตรงนี้นั่นเอง…
Garbage Collection in “JavaScript”
สำหรับ Garbage Collection ใน JavaScript นั้นเราไม่สามารถสั่งการมันแบบ manual ได้ มันจะทำงานของมันเอง โดยมีหลักคือ “Reachability” หรือก็คือตัวแปรหรือ Object ใดที่ไม่สามารถเข้าถึงได้จะถูกกำจัด
Mark and Sweep Algorithms
หลักการของ Garbage Collection ใน JavaScript คือการ Mark and Sweep คือให้มองโปรแกรมเป็น Tree แล้วเราก็ Travel ลงไปแล้ว Mark แต่ละ Node ที่ผ่าน เมื่อสิ้นสุดทุก Node แล้วก็ Sweep Node ที่เหลือที่ไม่ถูก Mark ออกไป
จริงๆแล้วใน JavaScript Engine เองยังมีการ Optimize ต่างๆภายในอีกมากมายเพื่อให้ Garbage Collection ทำงานได้อย่างรวดเร็วแต่เราเข้าใจแค่ Concept ของมันไว้ก็พอแล้วครับผม
Example By Code
ทีนี้มาลองเขียน code กันบ้าง จะได้เข้าใจกันมากขึ้นว่าจริงๆแล้ว Garbage Collection มันก็อยู่ในทุกส่วนของ code เรานั่นแหละ เพียงแต่เราไม่เห็นมันเท่านั้นเอง
let noom = {
name: 'noomerzx'
}let jack = {
name: 'jack'
}let nack = {
name: 'nack'
}jack.girlfriend = nack
nack.boyfriend = jacknoom.friend = jack
noom.sister = nack
จากตัวอย่าง code ข้างต้นเรามาลองแยก Node และคิดถึงความสัมพันธ์ในแต่ละ Node กันก่อน ซึ่งตอนนี้เรามี 3 Node คือ
- noom
- jack
- nack
จากนั้นเรามาดูความสัมพันธ์
- noom -> jack / noom -> nack
- jack -> nack
- nack -> jack
ทีนี้เราต้องมาแยกกันระหว่าง Reachable / Reference ก่อน
reachable: Node นั้นๆถูก Node อื่น reference ถึงหรือไม่
reference: Node นั้นๆ reference ไปถึง Node อื่นหรือไม่
ซึ่งการที่ Garbage Collection จะเข้าไป Mark ได้ Node นั้นจะต้องถูก “Reachable” เท่านั้น ดังนั้นจากตัวอย่าง Code ข้างต้นทุก Node ยังถูก Reachable อยู่ทำให้จะไม่โดน Garbage Collector ล้างข้อมูลออก แต่ถ้าเราเขียนเพิ่มว่า
delete jack.girlfriend
delete noom.sister
จะเกิดอะไรขึ้น ?? ผลก็ยังเหมือนเดิมเพราะแม้ nack จะไม่ถูก referance จาก Object ใดเลยแต่ Object nack ยังถูก Reachable โดย ตัวแปร nack ได้อยู่
nack = null
เมื่อเราสั่งให้ nack = null นั้น Object nack จะยังค้างอยู่ใน memory และเมื่อ Gabacge Collector ทำงานเจ้า Object นี้จะไม่ถูก Mark และจะถูก Sweep ไปในที่สุด ดังนั้นอย่าประกาศตัวแปรทิ้งขว้างกันนะครับเพราะถ้ามันยังถูก Reachable ได้มันก็จะยังคงค้างอยู่ใน Memory ตลอดกาลนาน
เข้าใจกันไหม ? มาลองเทสกันหน่อยซิ
let person = {
name: 'noomerzx'
}
let admin = person
person = null
จาก Code ข้างต้น Garbage Collection จะ Sweep Object ใดหรือไม่ (เฉลยใน Comment)
สรุป
- Garbage Collection ใน JavaScript จะทำงานด้วยตัวเอง ไม่สามารถสั่งได้
- Object ต่างๆจะยังคงอยู่ใน Memory ถ้ายังถูก Reachable
- การ Reference ไปถึง Node อื่นไม่ใช่การถูก Reachable
สุดท้ายผิดพลาดประการใดก็ แนะนำ ติชมใน Comment ได้เหมือนเดิมครับผม ใครอยากอ่านเต็มๆ แบบละเอียดยิบๆ กดเลย