Tutorial

รู้จักกับ Garbage Collection ใน Java

By Arnon Puitrakul - 17 มกราคม 2016

รู้จักกับ Garbage Collection ใน Java

เมื่อตอนที่ผมย้ายจากเขียน C แล้วมาเขียน Java ก็ทำให้สงสัยอยู่เรื่องนึงว่า "ใน Java มันมีคำสั่งที่ทำงานกับ Memory โดยตรงมั้ย ?" คำตอบที่ได้มาคือ ไม่มี เพราะ Principle ของตัว Java บอกว่า Robust + Secure เพราะฉะนั้น การที่ Java อนุญาติให้โปรแกรมเมอร์สามารถเข้าถึง Memory ได้โดยตรงอาจจะทำให้โปรแกรมของเรา พัง ได้ ดังนั้นตัว Java จึงต้องมีระบบตัวนึงที่เข้ามาช่วย Allocate และ Release Memory มันมีชื่อว่า Garbage Collection แต่ก่อนอื่นมาดูกันก่อนว่าปกติโปรแกรมที่รันผ่าน JVM จะจัดการ Memory ยังไง

JVM จัดการกับ Memory ยังไง ?

ก่อนที่เราจะไปรู้กันว่า รถขยะ ของเราทำงานกันอย่างไร เราจะต้องมารู้กันก่อนว่า ปกติแล้ว JVM จัดการ Memory ในเครื่องเวลารันอย่างไร
จากรูปด้านล่างเป็น Model คร่าว ๆ ในการ Allocate Memory ใน JVM โดยแบ่งออกเป็น 3 ส่วนใหญ่ ๆ นั่นคือ Heap, PremGen (Permanent Generation) และ Thread เรามาค่อย ๆ ดูกันทีล่ะส่วนกันดีกว่า

Garbage Collection 1

Heap เป็นส่วนที่เก็บ Object ที่สร้างมาจาก Class ต่าง ๆ ที่เราสั่งมันสร้างมาจากใน Code โดยจะแบ่งได้เป็นอีก 2 ประเภทย่อย นั่นคือ Old Generation และ New Generation โดยเราจะมาพูดถึงกันอีกครั้งตรง Garbage Collection เลยล่ะกัน เพราะว่า มันคือพระเอกของเราในวันนี้
PremGen หรือเราจะเรียกเต็ม ๆ ว่า Permanent Generation เป็นส่วนที่ใช้เก็บ แม่พิมพ์ ต่าง ๆ หรือ Class เพื่อรอให้โปรแกรมของเราเรียกใช้นั่นเอง โดยตัวมันเองอนุญาตให้ Thread อื่น ๆ สามารถเข้าถึงได้อีกด้วย (แหงแหละ ถ้า Thread อื่นเข้าถึงไม่ได้แล้วจะ ใช้ยังไง ?)
Thread อันนี้เป็น ส่วนของ Memory ที่ค่อนข้างที่จะเป็นส่วนตัวกว่าคนอื่นเขานิดนึง เพราะว่ามันจะเก็บข้อมูลที่ใช้ใน Thread ของตัวเองเท่านั้น ใครก็ห้ามยุ่ง Thread ใคร Thread มัน

Garbage Collection คืออะไร ?

มาถึงพระเอกของเราในวันนี้กันสักที เจ้าตัว Garbage Collection มันเป็นระบบตัวนึงที่อาศัยอยู่ใน JVM (Java Virtual Mechine) ที่คอยทำหน้าที่เป็น รถขยะ (ต่อจากนี้จะเรียกว่า รถขยะล่ะกันนะ !) มันจะคอยเก็บตัวแปร หรือ Object ที่ไม่ได้ถูกใช้แล้วออกไป เช่นถ้าโปรแกรมเรารัน Method นึงแล้วมี Local Variable อยู่ตัวนึง พอ Method นั้นรันจบ Garbage Collection ก็จะมารับ Local Variable ตัวนั้นออกไปและทำการคืนหน่วยความจำกลับสู่ระบบนั่นเอง
ขั้นตอนการทำงานของมันง่ายมาก ๆ อารมณ์เหมือนเครื่องกรองน้ำที่เขาเอามาขายกันเลย เริ่มแรกโปรแกรมของเราทำการสร้าง Object ขึ้นมา โดย Object ที่พึ่งสร้างไปก็จะอาศัยอยู่ในส่วนของ New Generation และก็จะเป็นแบบนี้เรื่อยไป
จนกระทั่งส่วนของ New Generation เต็มทีนี้ล่ะ Garbage Collection พระเอกของเราก็จะมาทำการเก็บกวาด Memory ที่อยู่ใน New Generation ออกไป โดยมันเข้าไปดูว่า Memory อันไหนที่ไม่ได้ใช้แล้วมันก็จะคืนให้ระบบทิ้งไป และส่วนที่ยังใช้อยู่มันก็จะย้ายไปที่ Old Generation ทันที เรื่องคร่าว ๆ ก็ประมาณนี้ล่ะ

ถังขยะนรกนี่จะทำงานเมื่อไหร่ ?

นึกถึงถังขยะบ้านพวกนายทั้งหลายน่ะ นายจะเอามันไปทิ้งเมื่อไหร่ล่ะ ? คำตอบคือ เมื่อใกล้มันเต็มไง มันถึงจะเอาไปทิ้ง ลองคิดต่อ ว่าถ้าเราต้องเอาขยะไปทิ้ง เราก็ต้องเสียเวลาเดินเอาไปทิ้งอีก ในคอมพิวเตอร์ก็เช่นกัน การที่ตัว JVM ของเรามันปล่อย Memory คืนให้ระบบ มันก็ย่อมต้องเสียเวลาเหมือนกัน
โดยปกติแล้วคุณ รถขยะของเรา นั้นจะทำงานอยู่ตลอดเลยนะ แต่ว่ามันจะถูกจัดให้อยู่ในส่วนงานที่ไม่สำคัญ (หรือก็คือ อู้อยู่) แต่เมื่อพอ Memory ใกล้เต็มเท่านั้นแหละ มันรีบลุกมาจัดการเลย แต่ถ้าไม่ทัน มันก็จะเกิด Exception ตัวนึง ที่เราเหล่าโปรแกรมเมอร์น่าจะเคยเจอมันอยู่บ่อย ๆ (มั้ง ?) นั่นคือ OutOfMemory นั่นเอง สะพรึงมั้ยล่ะ !!
อย่างที่บอกไปว่า การที่เราให้ ระบบเก็บขยะ เข้ามาทำงานนั้นก็จะเสียเวลาไป ที่เสียเวลาเป็นเพราะว่า เมื่อมันเข้ามาทำงานแล้ว ระบบจะจัดตัว ระบบเก็บขยะ ให้อยู่ในความสำคัญต้น ๆ เลย ทำให้ ตัวโปรแกรมของเราที่ควรจะรันไปเรื่อย ๆ กับต้องมา หยุดรอ ให้ รถขยะ ไปซะก่อน ทำให้เราเสียเวลานั่นเอง (ยิ่งเก็บเยอะ ก็ยิ่งเสียเวลานะ)
ถ้าถามว่า "ถ้ายิ่งเก็บเยอะยิ่งเสียเวลา เราก็ให้มันเก็บน้อย ๆ แต่บ่อยขึ้นสิ"
อันนี้เป็นความเชื่อที่ผิดนะ เพราะว่า ยิ่งถ้าเราปล่อย รถขยะ มาบ่อยขึ้นทำให้ ระบบที่ควรจะรันไปอย่างต่อเนื่องต้องมาชะงักกับ รถขยะ บ่อยขึ้นทำให้มันเซ็งมาก ๆ

สรุป

วันนี้เราก็ได้มาทำความรู้จักกับการจัดสรรหน่วยความจำใน JVM กันไป และรู้เพิ่มอีกอย่างว่า มันมีระบบอยู่ระบบนึงคอยจัดการกับ Memory ให้เราอยู่ข้างหลังนั่นคือ Garbage Collection ซึ่งเป็นระบบที่สำคัญมากกับการพัฒนาโปรแกรมขนาดใหญ่ในองค์กร หรือ แม้แต่ Android Application ด้วยก็เช่นกัน ถ้าไม่รู้เรื่องนี้ก็สามารถทำให้ App ที่เราสร้างออกมานั้นบรรลัยได้ ดันนั้นเรื่องนี้ถือว่าเป็นเรื่องที่มีความสำคัญมาก มาก มาก ใส่ดอกจันทร์สัก 20 ดอกได้เลย เพราะสำคัญจริง ๆ ในตอนหน้า เราจะมาดูกันว่า ลึก ๆ การทำงานของมันทำงานยังไง และเราจะนำสิ่งเหล่านี้มาทำให้โปรแกรมของเราดีขึ้นได้อย่างไร สำหรับวันนี้ สวัสดีครับ
สามารถดูข้อมูลเพิ่มเติมได้จาก Document ของ Java ตามลิงค์ด้านล่างได้เลย
Understanding Memory Management - Oracle

Read Next...

ติดตั้ง Zigbee Dongle บน Synology NAS กับ Home Assistant

ติดตั้ง Zigbee Dongle บน Synology NAS กับ Home Assistant

ก่อนหน้านี้เราเปลี่ยนมาใช้ Zigbee Dongle กับ Home Assistant พบว่าเสถียรขึ้นเยอะมาก อุปกรณ์แทบไม่หลุดออกจากระบบเลย แต่การติดตั้งมันเข้ากับ Synology DSM นั้นมีรายละเอียดมากกว่าอันอื่นนิดหน่อย วันนี้เราจะมาเล่าวิธีการเพื่อใครเอาไปทำกัน...

โหลด CSV วิธีไหนเร็วที่สุด ?

โหลด CSV วิธีไหนเร็วที่สุด ?

เมื่อหลายวันก่อนมีพี่ที่รู้จักกันมาถามว่า เราจะโหลด CSV ยังไงให้เร็วที่สุด เป็นคำถามที่ดูเหมือนง่ายนะ แต่พอมานั่งคิด ๆ ต่อ เห้ย มันมีอะไรสนุก ๆ ในนั้นเยอะเลยนี่หว่า วันนี้เราจะมาเล่าให้อ่านกันว่า มันมีวิธีการอย่างไรบ้าง และวิธีไหนเร็วที่สุด เหมาะกับงานแบบไหน...

ฮาวทู Sync Obsidian Note ด้วย LiveSync Plugin

ฮาวทู Sync Obsidian Note ด้วย LiveSync Plugin

ตั้งแต่ใช้ Obsidian เป็น App จด Note หลัก ชอบวิธีการจัดการมาก ๆ เมื่อใช้งานร่วมกับ Plugin ต่าง ๆ ยิ่งทำให้การใช้งานยืดหยุ่นมากกว่าเดิมอีกเยอะมาก ๆ ติดอยู่เรื่องเดียวคือ การใช้งานในหลาย ๆ อุปกรณ์ แต่เราเจอ Plugin ตัวนึงที่น่าสนใจมาก ๆ คือ LiveSync วันนี้เราจะมาเล่าวิธีการติดตั้ง และใช้งานมันกัน...

การสร้าง SSD Storage Pool บน Synology DSM

การสร้าง SSD Storage Pool บน Synology DSM

สำหรับคนที่ใช้ Synology NAS บางรุ่นจะมีช่อง M.2 สำหรับเสียบ NVMe SSD โดยพื้นฐาน Synology บอกว่ามันสำหรับการทำ Cache แต่ถ้าเราต้องการเอามันมาทำเป็น Storage ละ มันจะทำได้มั้ย วันนี้เราจะมาเล่าวิธีการทำกัน...