มีบทความสองสามบทความเกี่ยวกับวิธีการค้นหาหน่วยความจำรั่ว
แต่ถ้าสร้างขึ้นมาล่ะ?
ฉันคิดว่ามันจะเป็นแบบฝึกหัดที่น่าสนใจเพื่อให้คุณรู้ว่าหน่วยความจำรั่วใน 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 มีหน่วยความจำรั่วที่ทราบ ดังนั้นคุณอาจต้องการอัปเกรดหากคุณใช้เวอร์ชันเฉพาะนี้
คุณมีคำถามข้อเสนอแนะหรือเรื่องราวการดีบักหน่วยความจำรั่วที่น่าสนใจหรือไม่? แสดงความคิดเห็นด้านล่าง 🙂
ขอบคุณสำหรับการอ่าน!