เมื่อใดก็ตามที่คุณรันโค้ด คุณจะใช้หน่วยความจำ เมื่อคุณเขียนในภาษาเช่น Ruby ดูเหมือนว่าหน่วยความจำที่มีให้คุณนั้นไม่มีที่สิ้นสุด คุณสามารถดำเนินการต่อได้โดยไม่ต้องคิดถึงจำนวนหน่วยความจำคงที่ที่ระบบเรียกใช้โค้ดของคุณมี ในตอน Ruby Magic เราจะอธิบายวิธีการทำงาน!
เกร็ดประวัติศาสตร์
ย้อนกลับไปในสมัยนั้น ภาษาสคริปต์เช่น Ruby ยังไม่มีอยู่จริง ผู้คนเขียนโค้ดในภาษาเช่น C ซึ่งเป็นภาษาโปรแกรมระดับต่ำเท่านั้น สิ่งหนึ่งที่ทำให้ภาษาเหล่านี้อยู่ในระดับต่ำคือคุณต้องทำความสะอาดตัวเอง ตัวอย่างเช่น เมื่อใดก็ตามที่คุณจัดสรรหน่วยความจำเพื่อจัดเก็บ String
คุณต้องตัดสินใจด้วยว่าจะทำความสะอาดเมื่อใด
การล้างข้อมูลด้วยตนเอง
สิ่งนี้ดูคล้ายกับรหัส Ruby จำลองต่อไปนี้ มันประกาศตัวแปรและใช้วิธี free
– วิธีการนี้ไม่มีอยู่ใน Ruby – เพื่อล้างหน่วยความจำที่เราใช้หลังจากที่เราดำเนินการกับตัวแปรเสร็จแล้ว
1_000_000.times do |i|
variable = "Variable #{i}"
puts variable
free(variable)
end
วิธีการเขียนโปรแกรมที่น่าเบื่อ
คุณอาจรู้อยู่แล้วว่ามีความเสี่ยงที่นี่ ถ้าคุณลืม free
ตัวแปร? ในกรณีนั้น เนื้อหาของตัวแปรนั้นจะติดอยู่ในหน่วยความจำจนกว่ากระบวนการจะออก หากคุณทำเช่นนี้บ่อยพอ หน่วยความจำของคุณจะหมดและกระบวนการของคุณล่ม
ตัวอย่างต่อไปแสดงให้เห็นถึงปัญหาทั่วไปอื่น:
1_000_000.times do |i|
variable = "Variable #{i}"
free(variable)
puts variable
end
เราประกาศตัวแปรและ free
มัน. แต่แล้วเราก็พยายามใช้มันอีกครั้ง ซึ่งเป็นไปไม่ได้ เพราะมันไม่มีอยู่แล้ว หากเป็น C โปรแกรมของคุณจะขัดข้องด้วย segfault
. อ๊ะ!
มนุษย์เป็นเครื่องจักรที่ผิดพลาด
มนุษย์มีชื่อเสียงไม่ดีที่ไม่ทำผิดพลาดแบบนี้ตลอดเวลา จึงต้องมีวิธีการล้างหน่วยความจำโดยอัตโนมัติ วิธีที่นิยมที่สุดในการทำเช่นนี้ – ที่ใช้ใน Ruby– คือ Garbage Collection (GC)
วิธีการทำงานของการรวบรวมขยะ (GC)
ในภาษาที่ใช้ GC คุณสามารถสร้างออบเจ็กต์ได้โดยไม่ต้องล้างข้อมูลด้วยตนเอง เมื่อใดก็ตามที่คุณสร้างวัตถุ วัตถุนั้นจะถูกลงทะเบียนกับ Garbage Collector GC พยายามติดตามการอ้างอิงทั้งหมดที่คุณทำกับวัตถุนี้ เมื่อกำหนดว่าคุณไม่ได้ใช้วัตถุอีกต่อไปแล้ว วัตถุนั้นจะถูกทำเครื่องหมายเพื่อล้างข้อมูล Garbage Collector จะหยุดโปรแกรมของคุณชั่วคราวและล้างวัตถุที่ทำเครื่องหมายไว้ทั้งหมดเป็นระยะ
ดูตัวอย่างบางส่วน
ในวงง่าย ๆ ที่เราใช้ก่อนหน้านี้ งานของ GC นั้นค่อนข้างง่าย ทุกครั้งที่วนซ้ำตัวแปรจะไม่ถูกใช้ที่ใดอีกต่อไป สามารถทำเครื่องหมายตัวแปรเพื่อล้างข้อมูลได้ทันที
1_000_000.times do |i|
variable = "Variable #{i}"
puts variable
end
ในตัวอย่างต่อไป เราจะส่งตัวแปรไปยัง puts_later
วิธีที่รอ 30 วินาทีแล้ว puts
ตัวแปร
def puts_later(variable)
Thread.new do
sleep 30
puts variable
end
end
1_000_000.times do |i|
variable = "Variable #{i}"
puts_later variable
end
งานของ Garbage Collector ค่อนข้างซับซ้อนในตัวอย่างที่ค่อนข้างง่ายนี้ ต้องเข้าใจว่าเราอ้างอิงตัวแปรใน puts_later
กระบวนการ. เนื่องจากวิธีการเริ่มต้นเธรด Garbage Collector จึงต้องติดตามเธรดและรอให้เสร็จสิ้น จากนั้นจึงจะสามารถทำเครื่องหมายตัวแปรเพื่อล้างข้อมูลได้
เมื่อมันซับซ้อน
โดยไม่ต้องยกตัวอย่างที่ซับซ้อน เชื่อฉันเมื่อฉันพูดว่างานของ Garbage Collector นั้นยากจริงๆ สิ่งนี้ยังอธิบายด้วยว่าเหตุใด GC จึงอาจทำให้เกิดค่าใช้จ่ายและปัญหาในสภาพแวดล้อมการผลิตของคุณ จำเป็นต้องมีความเข้าใจอย่างละเอียดถึงสิ่งที่เกิดขึ้นในโปรแกรมของคุณเพื่อล้างหน่วยความจำอย่างเหมาะสม ซึ่งต้องใช้รอบ CPU ค่อนข้างน้อยจึงจะถูกต้อง แต่เดี๋ยวก่อน มันดีกว่าการทำความสะอาดหลังจากตัวคุณเอง!
ขยะยังมีอีกมาก
นี่เป็นเพียงการแนะนำของเราเกี่ยวกับการรวบรวมขยะ ในบทความต่อๆ ไป เราจะมาดูกันว่าสิ่งนี้ทำงานอย่างไรใน Ruby และคุณจะวัดและปรับแต่ง GC ได้อย่างไรเพื่อปรับปรุงประสิทธิภาพของแอปพลิเคชันของคุณ
อัปเดต: รับชมตอนต่อไปได้ที่นี่