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

ป้องกันการรั่วไหลของหน่วยความจำเมื่อเรียกใช้วิธี Ruby จากส่วนขยาย C

หน่วยความจำรั่วเป็นปัญหาสำหรับผู้ใช้อัญมณี ติดตามได้ยากและอาจนำไปสู่ต้นทุนโครงสร้างพื้นฐานที่มีราคาแพง

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

การใช้ 00 อย่างไร้เดียงสา อาจทำให้หน่วยความจำรั่วได้ ควรใช้ 18 จะดีกว่ามาก แทน ดังนั้น หากคุณเป็นผู้เขียนส่วนขยาย C โปรดอ่านต่อเพื่อประโยชน์ของนักพัฒนาที่จะใช้อัญมณีของคุณ

มาเริ่มกันเลย!

ปัญหาเกี่ยวกับ 23 และค

37 สามารถเป็นเครื่องมือที่ยอดเยี่ยมเมื่อคุณต้องการโต้ตอบระหว่าง Ruby และส่วน C ของไลบรารีของคุณ แต่ต้องเขียน C เพียงเล็กน้อยเท่านั้น

อย่างไรก็ตาม เมื่อคุณรัน 40 คุณไม่ได้อยู่ใน C อีกต่อไปแล้ว ซึ่งทุกอย่างตรงไปตรงมา คุณสามารถถูกทิ้งไว้ในน้ำโคลนได้หากฟังก์ชันที่เรียกว่า:

  1. เปลี่ยนคำจำกัดความโดยสิ้นเชิงในระหว่างรันไทม์
  2. ยกสาย

เบอร์ 1 เป็นตัวจับง่ายที่สุด คุณอาจจะจบลงด้วย segfault และหากชุดการทดสอบของคุณสมบูรณ์เพียงพอ คุณควรตรวจสอบก่อนที่จะเผยแพร่

อย่างไรก็ตาม อย่างหลังอาจทำให้หน่วยความจำรั่วและทำให้โค้ดเบสของคุณอ่านยากขึ้น มาดูกันตอนนี้เลย

เพิ่ม Ruby ทำให้เกิดการรั่วไหลของหน่วยความจำ C

กลไกการยกของ Ruby ข้ามระหว่างส่วนต่างๆ ของโค้ดจากขอบเขตหนึ่งไปยังพาเรนต์แรกที่ตรวจพบข้อผิดพลาด สิ่งนี้ถูกนำไปใช้ใน MRI โดยใช้ 52 และ 69 .

หากคุณสนใจเกี่ยวกับวิธีการสร้างสิ่งนี้ โปรดอ่านบท Evaluator ใน Ruby Hacking Guide โดยสรุป เมื่อคุณใช้ 72 บล็อก คุณ 89 และเมื่อคุณเพิ่มภายในบล็อกนี้ คุณจะ 90 ไปยังตำแหน่งที่บันทึกไว้

ดังนั้นหากฟังก์ชันถูกยกขึ้นด้วย 105 รหัส C ที่ถูกเรียกหลังจากนั้นไม่เคยดำเนินการ

ตัวอย่างด้านล่างแสดงให้เห็นถึงการรั่วไหลที่อาจเกิดขึ้น ถ้า 113 เพิ่มขึ้น มันจะรั่วไหล

 

แน่นอนว่าตัวอย่างข้างต้นค่อนข้างงี่เง่า — คุณสามารถกลับด้านส่วนการประมวลผล Ruby และ freeing ได้ อย่างไรก็ตาม สิ่งนี้ไม่สามารถทำได้เสมอไป และส่วนฟังก์ชันที่ยาวขึ้นก็สามารถเชื่อมโยงกันได้มากขึ้น

การใช้ 122 ใน Ruby

หากคุณใช้ Ruby คุณสามารถเขียนตัวอย่างข้างต้นโดยใช้131แทนได้ :

 

API นี้ยังมีให้บริการในภาษา C ด้วย 145 และ 154 :

 

อย่างไรก็ตาม ขั้นตอนนี้อาจยุ่งยากเล็กน้อย และหากคุณต้องการเพิ่ม 169 บล็อกไปที่ปาร์ตี้ มันจะอ่านน้อยลงมาก ฉันขอแนะนำให้อ่าน 'A Rubyist's Walk along the C-side (ตอนที่ 8):ข้อยกเว้นและการจัดการข้อผิดพลาด' ของ Peter Zhu หากคุณต้องการใช้ 173 API ใน C.

การใช้ 187 สำหรับค

มีอีกทางเลือกหนึ่ง ก่อนอื่น เรามาดูกันว่ามันจะมีลักษณะอย่างไรใน Ruby:

 

สิ่งนี้ดูแปลกใน Ruby แต่เป็นเวิร์กโฟลว์ที่เหมาะกับ C มาก MRI มี API สำหรับสิ่งนั้น 199 และฟังก์ชัน C มีลักษณะดังนี้:

 

วิธีการข้างต้นจะทำให้เกิดข้อผิดพลาด Ruby อีกครั้งหลังจากมีของว่างฟรี

โปรดทราบว่าเราสามารถเลือกที่จะเพิกเฉยต่อข้อผิดพลาดได้โดยใช้ anempty 208 บล็อกใน Ruby:

 

คำเตือน: หากคุณไม่ก่อให้เกิดข้อผิดพลาด 210 ขั้นตอนสำคัญ ดังนั้นคุณจึงไม่ต้องเก็บข้อมูลข้อผิดพลาดที่ผู้ใช้ไม่ควรทราบ

หรือคุณสามารถเลือกที่จะแจ้งข้อผิดพลาดตามเงื่อนไขได้ เช่น 221 :

 

คุณสามารถพิจารณา 234 ได้จริงๆ เช่นเดียวกับ 248 ตัวแปรร่วม

ทั้งหมดนี้เยี่ยมยอด แต่เมื่อเหลือเพียง 258 เท่านั้น เราจึงสามารถลดความซับซ้อนของ API นั้นได้

แนวคิดโดยรวมเบื้องหลังการใช้ 260 API เมื่อมีฟังก์ชั่นเพิ่มคือเพิ่มความสามารถในการอ่าน คุณไม่จำเป็นต้องตรวจสอบว่าฟังก์ชันสามารถเพิ่มได้หรือไม่ คุณถือว่าทำได้ และใช้สถานะเพื่อทำงานกับฟังก์ชันนั้น

272 ข้อเสนอ

มาแยก 281 กัน เนื่องจากเป็นสิ่งเดียวที่อันตราย วิธีการใช้ นี่คือ API ที่จะทำเช่นนั้น:

 

API นี้เหมือนกับ 296 โดยมี 309 จาก 313 . ดังนั้นการใช้งานจึงค่อนข้างตรงไปตรงมา:

 

API นี้ยังไม่มีให้บริการใน Ruby และอาจไม่มีให้บริการเลย คุณสามารถรับได้จาก RGeo (MIT LICENSE)

ตัวอย่างในโลกแห่งความเป็นจริง

หากคุณต้องการดูตัวอย่างในโลกแห่งความเป็นจริง ฉันขอแนะนำให้คุณอ่าน RGeocodebase เนื่องจากเราเพิ่งเปลี่ยนมาใช้เวอร์ชันเต็ม 327 . เรายังมีฟังก์ชันบางอย่าง เช่น 331 ที่เผยแพร่สถานะนี้เพื่อการใช้งานที่ง่ายขึ้น ฟังก์ชันนี้เป็นจุดเริ่มต้นที่ดีในการเริ่มต้นขุดค้น

อย่าลังเลที่จะเปิดประเด็นใน RGeo เพื่อหารือเกี่ยวกับตัวเลือกที่เราทำเพิ่มเติม

สรุป

ในโพสต์นี้ เราเตือนไม่ให้ใช้ 349 ด้วย C เพราะอาจทำให้หน่วยความจำรั่วได้ เราสำรวจโดยใช้ 357 หรือ 364 แทน.

ขอให้สนุกกับการเขียนโค้ด!

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

ยูลิสซี บูโอโนโม

Ulysse ผู้เขียนรับเชิญของเราคืออดีตนักพัฒนา Ruby ในอุตสาหกรรมที่อุทิศเวลาส่วนใหญ่ให้กับการเดินทางรอบโลก เวลาว่างของเขาทุ่มเทให้กับ RGeo และ Ruby และเขาชอบที่จะปรับแต่งระบบภายในของ Ruby

บทความทั้งหมดโดย Ulysse Buonomo