garbage-collection

Garbage collection คืออะไร (GC คืออะไร)

ก่อนที่จะพูดถึงว่า Java Garbage Collection คืออะไร ขออ้างอิงจากบทความเก่าที่เราทราบถึงการทำงานของ Java และ JVM กันไปแล้ว ทำให้เราทราบว่าการทำงานของ application จะอาศัยหน่วยความจำ หรือ Heap memory เป็นที่เก็บข้อมูล object ทั้งหลายเพื่อใช้งานภายใน ซึ่ง object เหล่านี้เมื่อถูกสร้างแล้วมักจะไม่มีการ clear ค่าภายใน code ซะส่วนใหญ่ ซึ่งทำให้ application นี้จะต้องจอง memory มากขึ้นเรื่อยๆ ซึ่งนั้นย่อมไม่เป็นเรื่องดีแน่ๆเพราะทรัพยากรเราเองก็มีอยู่อย่างจำกัด จึงเป็นที่มาของคำว่า GC  คืออะไร หรือ Garbage collection คืออะไร ซึ่งมันก็คือหลักการคืนหน่วยความจำ memory จาก object ที่ถูกสร้างขึ้นมาใช้งานและถูกทิ้งค้างไว้ โดยทำงานลบค่า reference ที่ link ระหว่างตัวแปร object และ value ออก และคืนเข้าสู่ Heap memory เพื่อนำเอาไปใช้งานสำหรับสร้าง object ใหม่ๆวนไปเรื่อยๆ โดยที่ไม่จำเป็นต้องขยายการจอง memory ตลอดไป

ทั้งหมดนี้เป็นส่วนหนึ่งของ Java Memory Management โดยใช้หลักการภายในด้วย garbage collection ซึ่งทำให้ developer ทั้งหลายสามารถสร้าง object ใหม่ๆโดยไม่ต้องกังวลเรื่องการ clear ค่าหรือข้อมูลที่ทำการจองไว้ เพราะ garbage collector จะทำหน้าที่คืนค่าพวกนี้กลับมาให้เอง ทำให้ code ที่เขียนกระชับสั้นขึ้นและทำงานได้ไวขึ้น ช่วยลดอาการ memory leak หรือ หน่วยความจำไม่เพียงพอ

ตอนนี้เราก็คงทราบแล้วว่า GC คืออะไร และด้วยกระบวนการทั้งหมดนี้ดูเหมือน Java garbage collection จะทำงานได้ดีมาก และแก้ปัญหาเรื่อง memory ได้เกือบหมด แต่ก็แลกมาด้วยปัญหาใหม่ด้วยคือ กระบวนการทำ garbage collection ย่อมมีความซับซ้อนและยากต่อการ optimize ตัวระบบ ซึ่งปัญหาที่ว่าคืออะไรนั้น เรามาดูการทำงานของ garbage collection กันก่อนดีกว่าว่าตัว Java Virtual Machine (JVM) เนี่ยทำ memory management อย่างไร

java-heap-memory

 

การทำงานของ Garbage collection (GC)

หลังจากที่ทราบแล้วว่า GC คืออะไร เรียบร้อยแล้ว หลายๆคนอาจจะคิดว่ากาทำ garbage collection ก็คือการทิ้งข้อมูลขยะ หรือ dead object ออกไปจาก heap memory แต่ในความเป็นจริงแล้ว Java Garbage Collection ทำตรงกันข้ามเพราะ มันจะทำการจำ object ที่ใช้งานเท่านั้น ส่วนที่เหลือทั้งหมดจะถูกตีเป็น garbage ทั้งหมด ซึ่งหลักการนี้นำมาซึ่งปัญหาเรื่อง performance ทันที

เราลองมาเริ่มต้นดูกันที่ heap memory ก่อนซึ่งเป็นส่วนที่ใช้เก็บข้อมูลที่มีการเปลียนแปลงตลอดเวลา ซึ่งตั้งแต่ตอนที่ start JVM ขึ้นมาระบบมักจะทำการสร้าง heap และจองพื้นที่ของ memory สำหรับใช้งานไว้เลย ส่งผลให้

  • การสร้าง object ทำได้ไวเพราะไม่ต้องทำการจองพื้นที่กับทาง OS ทุกครั้งที่สร้าง object ซึ่งสามารถเข้าใช้งานพื้นที่บน heap memory ได้ทันที อาศัยการทำ pointer ชี้ไปยังส่วนของพื้นที่ memory array จากนั้นก็การจองรอบถัดไปก็เพียงแค่เลื่อน offset ขึ้นไปใน array เรื่อยๆ
  • เมื่อ object ไม่ได้ใช้งานแล้ว ตัว garbage collector ก็จะดึงส่วนของ pointer ที่ชึ้ไปยัง พื้นที่ memory กลับไปเพื่อนำมาใช้งานให้จองใหม่อีกครั้ง นั้นหมายความว่า ข้อมูลจริงๆไม่ได้ถูกลบแต่อย่างใด และไม่ได้คือส่วนของ memory กลับไปให้ OS ด้วย

Object ทั้งหมดถูกจองบนพื้นที่ของ heap memory ซึ่งควบคุมโดย JVM รวมถึง class object, ตัวแปร static หรือตัว code ก็ถูกเก็บไว้ในนี้ ตราบที่ object เหล่านี้ยังมีการถูกอ้างอิง หรือ reference อยู่ ตัว JVM ก็จะถือว่า object เหล่านี้ยังถูกใช้งาน (Live object) แต่เมื่อใดที่ไม่มีการ reference แล้ว หรือ ไม่มีการใช้งานบน application code เจ้า garbage collector ก็จะลบ pointer มันออกและคืนพื่นที่ memory นั้นกลับไป

memory-allocation

 

Garbage Collection Root คืออะไร

หลังจากที่ทราบแล้วว่า memory ที่ใช้งานกันนี้เป็นเพียงแค่การ reference จาก object ลงไปหาค่าที่อยู่บนพื่นที่ memory ในลักษณะเหมือนใบไม้ที่เชื่อมต่อกันแต่ละกิ่งจนไปถึงราก (root) ตราบใดที่ application สามารถสร้าง link ไปถึง root ได้ ใบไม้นั้นก็ยังสามารถมีชีวิตอยู่ได้ ซึ่ง garbage collection ก็เรียก object เหล่านี้ว่า garbage-collection roots หรือ GC roots

 

GC roots มีด้วยกัน 4 ชนิดคือ

  • Local variables จะถูกเก็บและติดตามโดย thread เป็น stack
  • Active Java threads เป็น live object และ GC roots ซึ่งสำคัญมากสำหรับเป็นตัวแปรของ thread
  • Static variables ถูกอ้างอิงโดย class แต่ตัว class เองก็สามารถโดนทำ garbage collection ได้ นั้นหมายถึง static variable เองก็อาจจะโดยลบได้เช่นกัน ซึ่งเดี๋ยวจะอธิบายต่อไป
  • JNI References เป็น java object ที่สร้างโดย code ตัวเอง และถูกเก็บไว้แบบพิเศษ เพราะ JVM เองก็ไม่รู้ว่ามันถูก referenced โดย code หรือไม่

gc-roots

 

GC roots ใน Java application มีดังนี้

  • Local variables ภายใน main method
  • Main thread
  • Static variables ภายใน main class

 

การตัดสินใจ Mark หรือ ลบ object ใน Garbage collector

การจะตัดสินว่า object นั้นยังถูกใช้งานอยู่หรือไม่ เพื่อทำการ mark object ว่ายังถูกใช้งานหรือ Live object ไว้ ตัว JVM จะมีการรัน process ด้วยหลักการ mark-and-sweep algorithm โดยมีขั้นตอนดังนี้

  1. ตัว algorithm จะทำการไล่ object reference ทั้งหมด โดยเริ่มจาก GC roots และ mark object ที่ link ผ่านทั้งหมดได้ว่า Live object
  2. Heap memory ทั้งหมดที่ไม่ได้ถูก mark object ไว้ที่เหลือก็จะถูกคืนกลับ โดย mark ไว้ว่า free ซึ่งก็คือการกวาดเอา object ที่ไม่ใช้งานทิ้ง

Garbage Collection จึงมีส่วนช่วยปัญหาเรื่อง memory leak ได้แต่อย่างไรก็ตามมันก็ช่วยเรื่อง memory leak เฉพาะแบบปกติ เพราะบางครั้งก็เป็นไปได้ว่า object นั้นไม่ได้ถูกใช้งานแล้วแต่ก็ยังมี link ไปถึงค้างไว้ เพราะ developer อาจจะลืมที่จะลบ reference ที่อ้างอิงไว้อยู่ ทำให้ไม่ถูก garbage collection หรือแย่ไปกว่านั้นอาจจะหาสาเหตุไม่ได้ ต่อให้ใช้ software ช่วยก็ทำได้แค่แสดง object ที่น่าสงสัยเท่านั้น

gc-roots-with-memory-leak

 

ชนิดของ Garbage Collection

มีด้วยกัน 5 แบบ สำหรับการทำ Garbage Collection หรือ GC

  • Serial Collector
  • Parallel Collector
  • Parallel Compacting Collector
  • Concurrent Mark-Sweep (CMS) Collector
  • G1 Garbage Collector

 

gc

 

1. Serial Collector

การทำ Serial Collector นั้นทำด้วยหลักการ “Stop the World” ซึ่งหมายความว่า application ทั้งหมดจะหยุดทำงานไปชั่วขณะระห่วางที่ทำ garbage collection เหมาะสำหรับ application ที่ทำงานบนฝั่ง client  ซึ่งไม่ได้สนใจเรื่อง pause time ที่หยุดชั่วขณะ ซึ่งในความเป็นจริงแล้วมันสามารถใช้งานกับ application ปกติมากมายหลายแบบ เพราะการหยุด ใช้เวลาเพียงนิดเดียวและเกิดขึ้นเพียงแค่ครึ่งวินาที

ตั้งแต่ Java5 เป็นต้นมา serial collector ถูกตั้งเป็น default garbage collector หรือสามารถกำหนกได้ด้วย option

-XX:+UseSerialGC

 

2. Parallel Collector

Parallel Collector ถูกพัฒนาขึ้นมาเพื่อใช้ความสามารถในเรื่อง CPU ให้สูงขึ้นเพื่อให้ทำ garbage collection ได้รวดเร็ว เหมาะสำหรับ application ที่ทำงานบน harware ที่มี CPU มากกว่า 1 core และมีปัญหาเรื่อง pause time ที่ใช้เวลานาน เช่น งานพวก batch application หรือ billing process ที่ใช้ข้อมูลขนาดใหญ่มาประมวลผลทำให้ memory มีการจองขนาดใหญ่และใช้เวลาทำ garbage collection นาน วิธีนี้สามารถเอา CPU หลาย core มาช่วยทำ parallel ให้เร็วขึ้น โดยปกติจะถูกเลือกเป็น default ให้สำหรับเครื่องที่เป็น server-class หรือสามารถกำหนดจาก option

-XX:+UseParallelGC

 

3. Parallel Compacting Collector

Parallel Compacting collector ถูกพัฒนาให้มีประสิทธิภาพสูงขึ้นจาก Parallel Collector โดยใช้สูตร algorithm ใหม่ ในการทำ garbage collector สำหรับส่วนของ Old generations โดยเจ้า algorithm ที่ว่านี้พัฒนา step การทำ sweep phase ของ parallel collector ด้วย summary phase ซึ่งทำให้มีประสิทธิภาพกว่าเดิมเมื่อเปรียบเทียบกับ parallel collector ซึ่งก็ยังคงเหมาะสำหรับ hardware ที่มี CPU หลายๆ core โดยกำหนดการใช้งานด้วย option

XX:+UseParallelOldGC

 

 

4. Concurrent Mark Sweep Collector

สำหรับ Heap ที่มีขนาดใหญ่มาก การทำ garbage collection จะไม่ค่อยถี่ แต่จะใช้เวลานานในการทำ garbage collection เพื่อแก้ปัญหาตรงนี้จึงได้เพิ่มกระบวนการที่เรียกว่า concurrent mark-sweep (CMS) collector หรือที่เรียกกันว่า low-latency collector ซึ่งทำงานคล้ายๆกับ parallel collection แต่ใช้ CPU ที่สูงกว่าเพื่อแลกมาซึ่งความรวดเร็วและการทำงานที่เร็วขึ้น เหมาะกับการใช้งานประเภท

  • ต้องการเวลาขณะทำ garbage collection ที่สั้น
  • Application ที่สามารถใช้งาน CPU ร่วมกันได้พร้อมๆกัน
  • Application ที่มีขนาดของ Old generation ใหญ่มาก

CMS collector สามารถกำหนดได้จาก option

XX:+UseConcMarkSweepGC

 

 

5. G1 Garbage Collector

G1 garbage collector ถูกใช้สำหรับงานที่มี heap memory ขนาดใหญ่ โดยจะทำการแบ่ง heap memory ออกเป็นส่วน และทำงานเป็น parallel โดยที่ G1 จำทำการจัด heap memory ที่ว่างเอาไว้เป็นกลุ่มหลังจากที่ได้พื้นที่ว่างคืนมา ซึ่งต่างจาก CMS garbage collector ที่จะจัดกลุ่ม memory ตอนทำ STW หรือ Stop the Wold เท่านั้น โดย G1 collector ให้ความสำคัญกับการงานแบ่งตามพื้นที่เป็นลำดับแรก สามารถกำหนดได้จาก option

–XX:+UseG1GC

 

 

Author: Suphakit Annoppornchai

Credit: https://saixiii.com, https://www.dynatrace.com

One Thought to “GC คืออะไร Garbage collection คือ การคืนหน่วยความจำจาก object ที่ไม่ใช้งานแล้ว”

Leave a Reply