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

ทำความเข้าใจ Garbage Collection ใน Ruby: ภาค 1

ทุกครั้งที่คุณรันโค้ด คุณใช้หน่วยความจำ เมื่อคุณเขียนในภาษาแบบ Ruby ดูเหมือนว่าหน่วยความจำที่คุณมีนั้นไม่มีที่สิ้นสุด คุณสามารถทำงานต่อไปได้โดยไม่ต้องคิดถึงปริมาณหน่วยความจำที่คงที่ของระบบที่รันโค้ดของคุณ ในตอน Ruby Magic นี้ เราจะอธิบายว่ามันทำงานอย่างไร!

ประวัติสั้นๆ

ในอดีต ภาษาสคริปต์อย่าง Ruby ยังไม่มี คนเขียนโค้ดแค่ภาษาอย่าง C ภาษาโปรแกรมระดับต่ำ หนึ่งในสิ่งที่ทำให้ภาษาเหล่านี้เป็นระดับต่ำคือคุณต้องทำความสะอาดด้วยตัวเอง ตัวอย่างเช่น เมื่อคุณจัดสรรหน่วยความจำเพื่อจัดเก็บ String คุณต้องตัดสินใจด้วยว่าจะทำความสะอาดเมื่อไหร่

การทำความสะอาดด้วยมือ

สิ่งนี้ดูประมาณโค้ด Ruby เทียมนี้ มันประกาศตัวแปรและใช้เมธอッド free –เมธอด์นี้ไม่มีอยู่จริงใน Ruby– เพื่อทำความสะอาดหน่วยความจำที่เราใช้หลังจากเราใช้ตัวแปรเสร็จ

1_000_000.times do |i| variable = "Variable #{i}" puts variable free(variable) end

วิธีเขียนโปรแกรมที่น่าเบื่อ

คุณอาจตระหนักแล้วว่ามีความเสี่ยงตรงนี้: ถ้าคุณลืม free ตัวแปร? ในกรณีนั้น เนื้อหาของตัวแปรนั้นจะค้างอยู่ในหน่วยความจำจนกระทั่ง process จบ ถ้าทำอย่างนี้บ่อยพอ คุณจะหมดหน่วยความจำและ process จะแครช

ตัวอย่างต่อไปแสดงอีกปัญหาทั่วไป:

1_000_000.times do |i| variable = "Variable #{i}" free(variable) puts variable end

เราประกาศตัวแปรและ free มัน แล้วเราพยายามใช้มันอีกครั้ง ซึ่งเป็นไปไม่ได้เพราะมันไม่มีอยู่แล้ว ถ้าเป็น C โปรแกรมของคุณจะแครชพร้อม segfault โอ้!

มนุษย์คือเครื่องจักรทำผิดพลาด

มนุษย์แย่มากในการไม่ทำผิดพลาดประเภทนี้ตลอดเวลา ดังนั้นจึงต้องมีวิธีทำความสะอาดหน่วยความจำอัตโนมัติ วิธีที่นิยมที่สุด –ที่ Ruby ใช้ด้วย– คือ Garbage Collection (GC)

Garbage Collection (GC) ทำงานอย่างไร

ในภาษาที่ใช้ GC คุณสามารถสร้างอ็อบเจ็กต์ได้โดยไม่ต้องทำความสะอาดด้วยมือ ทุกครั้งที่คุณสร้างอ็อบเจ็กต์ มันจะลงทะเบียนกับ Garbage Collector GC พยายามติดตามการอ้างอิงทั้งหมดที่คุณทำไปยังอ็อบเจ็กต์นี้ เมื่อมันตัดสินว่าคุณไม่ได้ใช้อ็อบเจ็กต์อีกต่อไป มันจะ mark ไว้เพื่อทำความสะอาด ทุกๆ ครั้ง Garbage Collector จะหยุดโปรแกรมของคุณชั่วคราวและทำความสะอาดอ็อบเจ็กต์ที่ mark ไว้ทั้งหมด

ดูตัวอย่างบางอย่าง

ในลูปง่ายๆ ที่เราใช้ก่อนหน้านี้ งานของ GC ค่อนข้างง่าย ในแต่ละรอบของลูป ตัวแปรไม่ได้ถูกใช้ที่ไหนเลย ตัวแปรสามารถ mark เพื่อทำความสะอาดได้ทันที

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 เพราะเมธอด์เริ่ม thread Garbage Collector ต้องติดตาม thread และรอจนมันจบ แล้วตัวแปรถึงจะ mark เพื่อทำความสะอาดได้

เมื่อมันซับซ้อน

โดยไม่ได้เข้าไปในตัวอย่างซับซ้อน ขอเชื่อผมได้ว่า งานของ Garbage Collector ยากมาก นี่ยังอธิบายได้ว่า ทำไม GC ถึงก่อให้เกิด overhead และปัญหาใน production environment ของคุณ มันต้องมีความเข้าใจรายละเอียดมากเกี่ยวกับสิ่งที่เกิดขึ้นในโปรแกรมของคุณเพื่อทำความสะอาดหน่วยความจำให้ถูกต้อง ซึ่งใช้ CPU cycles ค่อนข้างมาก แต่นั่นดีกว่าทำความสะอาดด้วยตัวเอง!

Garbage Collection ยังมีอะไรมากกว่านี้

นี่เป็นเพียงการแนะนำ Garbage Collection ในบทความหน้า เราจะดูว่ามันทำงานใน Ruby อย่างไร แบบแน่นอน และว่าคุณสามารถวัดและปรับ GC เพื่อปรับปรุงประสิทธิภาพแอปพลิเคชันของคุณได้อย่างไร

อัปเดต:ตอนถัดไปพร้อมอ่านได้ที่นี่