มีบทความสองสามบทความเกี่ยวกับวิธีการค้นหาหน่วยความจำรั่ว
แต่ถ้าสร้างขึ้นมาล่ะ?
ฉันคิดว่ามันจะเป็นแบบฝึกหัดที่น่าสนใจเพื่อให้คุณรู้ว่าหน่วยความจำรั่วใน Ruby เป็นอย่างไร
มาดูตัวอย่างกัน
หลุดง่าย
เราสร้างหน่วยความจำรั่วได้โดยการเพิ่มวัตถุใหม่ลงในอาร์เรย์
ถูกใจสิ่งนี้ :
a = [] b = {} loop { sleep(1) 10_000.times { a << "abc" } puts GC.stat(b)[:heap_live_slots] }
สิ่งนี้สร้างสตริง 10k ทุกวินาที &จะพิมพ์จำนวนอ็อบเจ็กต์:
285051 295052 305053 315054 325055 335056 345057 355058
จำนวนที่เพิ่มขึ้นเรื่อย ๆ เนื่องจาก GC ไม่สามารถรวบรวมสตริงเหล่านี้ได้ พวกเขากำลังอ้างอิงโดยอาร์เรย์ที่มี (a
)
ถ้า a
อยู่นอกขอบเขตที่จะอนุญาตให้ GC รวบรวม "abc"
. เหล่านี้ทั้งหมด สตริง คุณสามารถทดสอบสิ่งนี้ด้วยตัวอย่างด้านบนโดยการตั้งค่า a
ให้เป็นศูนย์ จากนั้นเรียกใช้ GC.start
.
คุณสามารถดูตัวอย่างสดได้ที่นี่ เพียงคลิก run
เพื่อดูผลลัพธ์
การรั่วไหลของส่วนขยาย C
เมื่อคุณสร้างวัตถุจาก Ruby GC จะติดตามจำนวนหน่วยความจำที่ใช้ แต่เมื่อใช้ส่วนขยาย C Ruby จะไม่สามารถควบคุมสิ่งที่เกิดขึ้นได้
หากคุณสร้างส่วนขยาย C แบบนี้:
#include <ruby.h> #include "extconf.h" void *ptr; void Init_extension() { allocate_memory(); } void allocate_memory() { for(int i = 0; i < 10000; i++) { ptr = malloc(1000); } }
allocate_memory()
ฟังก์ชันจะทำให้หน่วยความจำรั่วเพราะใช้ malloc
และไม่โทรfree
เพื่อปลดปล่อยความทรงจำนั้นออกมา
ดังที่คุณเห็นที่นี่:
`ps -o rss -p #{$$}`.lines.last # "49036" require './extension' `ps -o rss -p #{$$}`.lines.last # "89512"
การรั่วไหลประเภทนี้จะไม่ปรากฏใน heap dump หรือใน GC.stat
แต่คุณจะเห็นการใช้หน่วยความจำเพิ่มขึ้น
สรุป
ตอนนี้คุณรู้แล้วว่าหน่วยความจำรั่วเป็นอย่างไร หวังว่าจะช่วยให้คุณค้นหาได้เร็วขึ้นหากคุณเคยประสบปัญหานี้ Btw Ruby 2.4.1 มีหน่วยความจำรั่วที่ทราบ ดังนั้นคุณอาจต้องการอัปเกรดหากคุณใช้เวอร์ชันเฉพาะนี้
คุณมีคำถามข้อเสนอแนะหรือเรื่องราวการดีบักหน่วยความจำรั่วที่น่าสนใจหรือไม่? แสดงความคิดเห็นด้านล่าง 🙂
ขอบคุณสำหรับการอ่าน!