Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

เจาะลึก Garbage Collection ของ Ruby: การทำงานของ MRI แบบละเอียด

ในตอนก่อนหน้าของ Ruby Magic เราพูดถึงว่าทำไมต้องมี Garbage Collection (GC) และการทำงานโดยทั่วไป ในโพสต์นี้เราจะเจาะลึกเข้าไปในการนำไปใช้งานใน Ruby

การนำ Ruby มาใช้งานต่างๆ

มีการนำ Ruby มาใช้งานหลายรูปแบบ สามตัวที่นิยมคือ MRI (Matz's Ruby Interpreter), Rubinius และ JRuby การนำ Ruby มาใช้งานต่างกันใช้วิธี GC ต่างกัน ในบทความนี้เราจะเน้นที่ MRI ซึ่งเป็นสิ่งที่นักพัฒนา Ruby ส่วนใหญ่ใช้

Heap ของ Ruby

คอมพิวเตอร์มีหน่วยความจำ 2 ประเภท: Stack และ Heap Stack เร็วมากและเป็น local ในบริบทของการเรียกฟังก์ชัน หมายความว่าตัวแปรที่ประกาศใน stack จะถูกปลดทันทีเมื่อฟังก์ชันจบ Stack จำกัดขนาดมาก จึงไม่สามารถจัดเก็บอ็อบเจ็กต์ขนาดใหญ่ที่มีข้อมูลรูปภาพหรือไฟล์ได้

สิ่งนี้ไม่เหมาะกับการจัดเก็บอ็อบเจ็กต์ Ruby อ็อบเจ็กต์เหล่านี้มักคงอยู่เกินกว่าการเรียกเมธอッド นอกจากนี้ ยากเกือบจะคาดการณ์ว่าอ็อบเจ็กต์จะใหญ่เกินกว่า stack หรือไม่

ดังนั้น Ruby จึงใช้หน่วยความจำอีกประเภท: heap บน heap โปรแกรมสามารถขอหน่วยความจำบางส่วน และรับผิดชอบทำความสะอาดเมื่อใช้เสร็จ Ruby ใช้สิ่งนี้โดยการขอ slab หน่วยความจำเดียวเพื่อจัดเก็บอ็อบเจ็กต์ Ruby เรียกว่า heap ของ Ruby

สรุป Stack และ Heap
หน่วยความจำ Stackเร็วมาก
หน่วยความจำที่ใช้ถูกปลดอัตโนมัติเมื่อการเรียกฟังก์ชันจบ
จำกัดขนาดมาก
หน่วยความจำ Heapช้ากว่า stack เล็กน้อย
ไม่มีการทำความสะอาดอัตโนมัติ
ขนาดจำกัดเพียงแค่หน่วยความจำที่มีอยู่ของคอมพิวเตอร์

ดังนั้น อ็อบเจ็กต์ Ruby จะถูกจัดสรรบน heap ของ Ruby เสมอ หากขนาดเล็กกว่า 40 ไบต์ เนื้อหาสามารถฝังอยู่ในอ็อบเจ็กต์ได้โดยตรง มิฉะนั้น อ็อบเจ็กต์จะชี้ไปยังส่วนหน่วยความจำแยกบน heap ของ Ruby อ็อบเจ็กต์ Ruby ของคุณมักจัดเก็บอยู่ในสองตำแหน่งที่ต่างกันในหน่วยความจำ เมื่อ heap ของ Ruby เต็ม จะสร้าง heap ใหม่สำหรับอ็อบเจ็กต์ใหม่

Mark and Sweep

MRI ใช้อัลกอริทึม GC ที่เรียกว่า Mark and Sweep ทำงานโดยทำ mark phase ก่อน ใน mark phase Garbage Collector จะสแกนอ็อบเจ็กต์ที่มีอยู่ทั้งหมดและตั้งค่า flag marked บนทุกอ็อบเจ็กต์ที่เชื่อว่าสามารถทำความสะอาดได้

Mark phase หยุดการทำงานของโค้ดของคุณ เหตุผลคือ Garbage Collector ต้องเข้าใจความสัมพันธ์ระหว่างอ็อบเจ็กต์ทั้งหมดที่มีอยู่ หากโปรแกรมทำงานระหว่างกระบวนการ mark สิ่งต่างๆ อาจเปลี่ยนแปลงและ Garbage Collector จะไม่แน่ใจเกี่ยวกับสถานะปัจจุบันของอ็อบเจ็กต์

ثانيًا sweep phase เริ่มต้น ทำงานในพื้นหลังบน Ruby 1.9 ขึ้นไป Garbage Collector ปลดอ็อบเจ็กต์ที่ถูก mark ใน mark phase ทีละน้อย หน่วยความจำจะพร้อมใช้งานอีกครั้งหลัง sweep เสร็จ

เนื่องจาก mark phase หยุดการทำงานของโค้ด นี่คือจุดที่ปัญหาใน production อาจเกิดขึ้น sweep phase ค่อนข้างเป็นกลาง

สรุป Mark and Sweep
Mark phaseสแกนอ็อบเจ็กต์ที่มีอยู่
ตั้งค่า mark flag หากอ็อบเจ็กต์สามารถทำความสะอาดได้
หยุดการทำงานของโค้ด
Sweep phaseทำงานในพื้นหลัง
ทำความสะอาดอ็อบเจ็กต์ที่ถูก mark
หน่วยความจำพร้อมใช้งานอีกครั้งหลัง sweep เสร็จ

Major และ Minor GC runs

ใน Ruby 2.1+ Garbage Collector ทำ major และ minor runs มันติดตามว่าอ็อบเจ็กต์ไหนใหม่ หากอ็อบเจ็กต์รอดชีวิตผ่าน GC runs หลายครั้ง จะถูก mark ว่าเก่า อ็อบเจ็กต์เก่าจะถูกละเลยใน minor runs ทำให้ minor runs น้อยกว่าการรบกวน เพราะ Garbage Collector ต้องสแกนเฉพาะอ็อบเจ็กต์ที่เพิ่งจัดสรร

สิ่งนี้มีประโยชน์เพราะบ่อยครั้งที่ส่วนหนึ่งของหน่วยความจำไม่ควรถูกทำความสะอาด เมื่อคุณ boot Rails มันโหลด Rails framework ทั้งหมดเข้าหน่วยความจำ นั่นจะอยู่ตลอดอายุการทำงาน จึงจะเป็นการสูญเปล่าทรัพยากรที่จะตรวจสอบอ็อบเจ็กต์เหล่านี้ทุกครั้ง

Major และ Minor runs
Major runรันน้อยกว่า
รันได้ยากกว่า
Minor runละเลยอ็อบเจ็กต์เก่า
รันบ่อยกว่า
รบกวนน้อยกว่า

สำหรับผู้ที่อยากเจาะลึกกว่า

เราเรียนรู้มากมายจากบล็อกของ Aman Gupta ดูสิ้นั้นถ้าอยากเจาะลึกเรื่องนี้เพิ่มเติม

ตอนหน้า: การปรับ Garbage Collection เชิงปฏิบัติ

มีเมตริกหลายอย่างที่คุณสามารถวัดและการเปลี่ยนแปลงการตั้งค่าที่สามารถทำได้เพื่อปรับแต่งการทำงานของ Garbage Collector ในตอนหน้าของซีรีส์ GC นี้ เราจะพูดถึงเมตริกและพารามิเตอร์การตั้งค่าเหล่านี้