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

ข้อมูลเบื้องต้นเกี่ยวกับการเก็บขยะ (ตอนที่ 2)

ในตอนก่อนหน้าของ 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 นี้ เราจะพูดถึงเมตริกและพารามิเตอร์การกำหนดค่าเหล่านี้