ในตอนก่อนหน้าของ Ruby Magic เราได้พูดถึงสาเหตุที่เราต้องการ Garbage Collection (GC) และวิธีการทำงานโดยทั่วไป ในโพสต์นี้ เราจะเจาะลึกลงไปอีกเล็กน้อยเกี่ยวกับวิธีการใช้งาน Ruby
การใช้งาน Ruby ที่แตกต่างกัน
มีการใช้งาน Ruby จำนวนมาก สามรายการยอดนิยมคือ:MRI (Matz's Ruby Interpreter), Rubinius และ JRuby การใช้งาน Ruby ที่แตกต่างกันใช้วิธีการต่างๆ ของ GC ในบทความนี้ เราจะเน้นที่ MRI ซึ่งเป็นสิ่งที่นักพัฒนา Ruby ส่วนใหญ่ใช้
กองทับทิม
คอมพิวเตอร์มีหน่วยความจำสองประเภท:Stack และ Heap สแต็กนั้นเร็วมากและอยู่ในบริบทของการเรียกใช้ฟังก์ชัน ซึ่งหมายความว่าทุกตัวแปรที่ประกาศในสแต็กจะว่างทันทีเมื่อฟังก์ชันเสร็จสิ้น สแต็กมีขนาดจำกัดมาก คุณจึงไม่สามารถจัดเก็บวัตถุขนาดใหญ่ที่มีรูปภาพหรือข้อมูลของไฟล์ได้ เป็นต้น
นี้ไม่เหมาะสมสำหรับการจัดเก็บวัตถุทับทิม ออบเจ็กต์เหล่านี้มักจะติดอยู่นานกว่าการเรียกใช้เมธอด นอกจากนี้ แทบจะเป็นไปไม่ได้เลยที่จะคาดเดาว่าอ็อบเจกต์จะใหญ่เกินไปสำหรับสแต็กหรือไม่
ดังนั้น Ruby จึงใช้หน่วยความจำประเภทอื่น:ฮีป ในฮีปโปรแกรมสามารถอ้างสิทธิ์หน่วยความจำบางส่วนและรับผิดชอบการล้างข้อมูลเมื่อเสร็จสิ้นด้วยหน่วยความจำนั้น Ruby ใช้สิ่งนี้โดยอ้างสิทธิ์หน่วยความจำแผ่นเดียวเพื่อใช้เก็บวัตถุ Ruby นี่เรียกว่ากองทับทิม
สรุปสแต็กและฮีป | |
---|---|
หน่วยความจำสำรอง | เร็วมาก หน่วยความจำที่ใช้จะว่างโดยอัตโนมัติเมื่อสิ้นสุดการเรียกใช้ฟังก์ชัน ขนาดจำกัดมาก |
หน่วยความจำฮีป | ช้ากว่าสแต็คเล็กน้อย ไม่มีการล้างข้อมูลอัตโนมัติ ขนาดถูกจำกัดโดยหน่วยความจำที่มีอยู่ของคอมพิวเตอร์ |
ดังนั้นวัตถุ Ruby จะถูกจัดสรรบนฮีปของ Ruby เสมอ หากมีขนาดเล็กกว่า 40 ไบต์ สามารถฝังเนื้อหาลงในวัตถุได้โดยตรง มิฉะนั้น วัตถุจะชี้ไปยังส่วนหน่วยความจำแยกต่างหากบนฮีปของ Ruby ดังนั้นวัตถุ Ruby ของคุณจึงมักถูกเก็บไว้ในหน่วยความจำสองตำแหน่งที่แตกต่างกันโดยสิ้นเชิง เมื่อกอง Ruby เต็ม มันจะสร้าง heap ใหม่ ซึ่งใช้สำหรับวัตถุใหม่
ทำเครื่องหมายและกวาด
MRI ใช้อัลกอริทึม GC ที่เรียกว่า Mark and Sweep การดำเนินการนี้ทำโดยการทำระยะเครื่องหมายก่อน ในระยะทำเครื่องหมาย Garbage Collector จะสแกนวัตถุที่มีอยู่ทั้งหมดในปัจจุบันและตั้งค่าสถานะที่ทำเครื่องหมายไว้บนทุกวัตถุที่เชื่อว่าสามารถทำความสะอาดได้
ระยะเครื่องหมายจะหยุดการทำงานของโค้ดของคุณ เหตุผลก็คือ Garbage Collector ต้องเข้าใจความสัมพันธ์ทั้งหมดระหว่างวัตถุที่มีอยู่ หากโปรแกรมทำงานในระหว่างกระบวนการทำเครื่องหมาย สิ่งต่างๆ อาจเปลี่ยนแปลงได้ในระหว่างนี้ และ Garbage Collector จะไม่แน่ใจว่าสถานะปัจจุบันของวัตถุเป็นอย่างไร
ประการที่สอง ระยะการกวาดเริ่มต้นขึ้น สิ่งนี้ทำงานในพื้นหลังบน Ruby 1.9 ขึ้นไป Garbage Collector จะปล่อยวัตถุทุกชิ้นที่ถูกทำเครื่องหมายไว้ในระยะทำเครื่องหมายอย่างเงียบ ๆ หน่วยความจำจะใช้ได้อีกครั้งหลังจากการกวาดเท่านั้น
เนื่องจากเฟสมาร์กจะหยุดการทำงานของโค้ดของคุณ จึงเป็นจุดที่เกิดปัญหาในการผลิตได้ ระยะการกวาดค่อนข้างไม่เป็นพิษเป็นภัย
ทำเครื่องหมายและกวาดสรุป | |
---|---|
มาร์คเฟส | สแกนวัตถุที่มีอยู่ ตั้งค่าสถานะเครื่องหมายหากวัตถุสามารถล้างได้ หยุดการเรียกใช้โค้ด |
ระยะการกวาด | ทำงานในพื้นหลัง ล้างวัตถุที่ทำเครื่องหมายไว้ หน่วยความจำพร้อมใช้งานอีกครั้งหลังจากแข่งขันการกวาดแล้ว |
การรัน GC หลักและรอง
ใน Ruby 2.1+ นั้น Garbage Collector จะทำการวิ่งทั้งรายใหญ่และรายย่อย มันติดตามว่าวัตถุใดเป็นของใหม่ หากวัตถุรอดจากการรัน GC สองสามรายการ จะมีการทำเครื่องหมายว่าเก่า วัตถุเก่าจะถูกละเว้นในการรันรอง สิ่งนี้ทำให้ผู้เยาว์ทำงานล่วงล้ำน้อยลงมากเนื่องจาก Garbage Collector ต้องสแกนเฉพาะวัตถุที่เพิ่งได้รับการจัดสรร
สิ่งนี้มีประโยชน์เพราะบ่อยครั้งที่หน่วยความจำของคุณไม่ควรถูกล้าง เมื่อคุณบูต Rails มันจะโหลดเฟรมเวิร์ก Rails ทั้งหมดลงในหน่วยความจำ ซึ่งจะคงอยู่ที่นั่นตลอดชีวิต ดังนั้นจึงเป็นการสิ้นเปลืองทรัพยากรในการตรวจสอบวัตถุเหล่านี้ทุกครั้ง
การรันหลักและรอง | |
---|---|
วิ่งหลัก | วิ่งน้อยลง วิ่งหนักขึ้น |
วิ่งน้อย | ไม่สนใจวัตถุเก่า เรียกใช้บ่อยขึ้น รบกวนการทำงานน้อยลง |
สำหรับผู้ที่ต้องการดำน้ำลึก
เราเรียนรู้มากมายเกี่ยวกับเรื่องนี้จากบล็อกที่ยอดเยี่ยมของ Aman Gupta ตรวจสอบว่าคุณต้องการเจาะลึกเรื่องนี้หรือไม่
ถัดไป:การปรับแต่งการรวบรวมขยะในทางปฏิบัติ
มีเมตริกจำนวนหนึ่งที่คุณสามารถวัดและกำหนดค่าการเปลี่ยนแปลงที่คุณสามารถทำได้เพื่อปรับแต่งวิธีการทำงานของ Garbage Collector ในภาคถัดไปของซีรีส์ GC นี้ เราจะพูดถึงเมตริกและพารามิเตอร์การกำหนดค่าเหล่านี้