กำจัดวัตถุอย่างถูกต้องเมื่อเซิร์ฟเวอร์ถูกยกเลิก


9

ฉันกำลังทำงานในโครงการ C ++ ขนาดใหญ่ ประกอบด้วยในเซิร์ฟเวอร์ที่เปิดเผย REST API ให้ส่วนติดต่อที่เรียบง่ายและใช้งานง่ายสำหรับระบบที่กว้างมากซึ่งประกอบด้วยเซิร์ฟเวอร์อื่น ๆ codebase นั้นค่อนข้างใหญ่และซับซ้อนและพัฒนาไปตามกาลเวลาโดยไม่มีการออกแบบที่เหมาะสม งานของฉันคือการใช้คุณสมบัติใหม่และ refactor / แก้ไขรหัสเก่าเพื่อให้มีเสถียรภาพและเชื่อถือได้มากขึ้น

ในขณะนี้เซิร์ฟเวอร์สร้างวัตถุที่มีอายุยืนยาวจำนวนหนึ่งซึ่งไม่เคยยกเลิกหรือกำจัดเมื่อกระบวนการยุติลง สิ่งนี้ทำให้ Valgrind เกือบจะใช้การไม่ได้สำหรับการตรวจจับการรั่วไหลเนื่องจากเป็นไปไม่ได้ที่จะแยกแยะระหว่างการรั่วไหลที่ถูกต้องตามกฎหมายนับพันจากการ "ที่อันตราย"

ความคิดของฉันคือการตรวจสอบให้แน่ใจว่าวัตถุทั้งหมดถูกกำจัดก่อนที่จะถูกยกเลิก แต่เมื่อฉันทำข้อเสนอนี้เพื่อนร่วมงานและเจ้านายของฉันไม่เห็นด้วยฉันชี้ให้เห็นว่าระบบปฏิบัติการจะเพิ่มหน่วยความจำนั้นต่อไป จะทำให้การปิดเซิร์ฟเวอร์ช้าลง (ซึ่งในขณะนี้เป็นการเรียกไปยังstd::exit) ฉันตอบว่าการมีขั้นตอนการปิด "สะอาด" ไม่ได้แปลว่าต้องใช้ เราสามารถโทรstd::quick_exitหรือkill -9ดำเนินการได้ตลอดเวลาหากเรารู้สึกใจร้อน

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

คุณคิดยังไง? ฉันกำลังพยายามอย่างไม่มีจุดหมายหรือไม่? ถ้าไม่ฉันจะโน้มน้าวใจเพื่อนร่วมงานและเจ้านายของฉันได้อย่างไร ถ้าเป็นเช่นนั้นทำไมและควรทำอย่างไร


นอกเหนือจากข้อโต้แย้งด้านประสิทธิภาพ (ซึ่งสมเหตุสมผลแล้ว) มันมีความพยายามอย่างมากที่จะแยกวัตถุที่มีชีวิตยืนยาวและเพิ่มรหัสทำความสะอาดสำหรับพวกมันหรือไม่?
Doc Brown

คำตอบ:


7

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

เรามีกระบวนการทำงานที่ยาวนานซึ่งใช้เวลาหลายนาทีในการเผยแพร่วัตถุนับพันรายการ มันมีประสิทธิภาพมากกว่าเพียงแค่ออกจากและปล่อยให้พวกเขาตาย น่าเสียดายที่คุณระบุว่าสิ่งนี้ทำให้ยากต่อการตรวจสอบการรั่วไหลของหน่วยความจำที่แท้จริงด้วย valgrind หรือเครื่องมืออื่น ๆ

นี่คือการประนีประนอมที่ดีสำหรับการทดสอบของเราในขณะที่ไม่ส่งผลกระทบต่อประสิทธิภาพปกติ


1
+1 ลัทธิปฏิบัตินิยม FTW มีค่าในการวัด แต่ยังมีค่าในการปิดอย่างรวดเร็ว
Ross Patterson

2
เป็นอีกทางเลือกหนึ่งสำหรับสวิตช์บรรทัดคำสั่งคุณอาจต้องการใช้การลบวัตถุถาวรภายในบล็อก #ifdef DEBUG
จูลส์

3

กุญแจสำคัญในที่นี้คือ:

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

สิ่งนี้บอกเป็นนัยได้โดยตรงว่า codebase ของคุณนั้นถูกปูด้วยกันจากความหวังและสตริง โปรแกรมเมอร์ C ++ ที่มีความสามารถไม่มีอิสระสองเท่า

คุณกำลังพยายามอย่างไร้จุดหมายเช่นเดียวกับที่คุณกำลังเผชิญกับปัญหาเล็ก ๆ น้อย ๆ อย่างหนึ่งของปัญหาที่เกิดขึ้นจริงซึ่งก็คือรหัสของคุณมีความน่าเชื่อถือเท่ากับโมดูลบริการ Apollo 13

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


แน่นอนปัญหาอยู่ในภาพรวม อย่างไรก็ตามมันหายากมากที่หนึ่งสามารถค้นหาทรัพยากรและสิทธิ์ในการ refactor / rewrite โครงการให้รูปร่างดีขึ้น
Cengiz สามารถ

@CengizCan: หากคุณต้องการแก้ไขข้อบกพร่องคุณต้อง refactor มันเป็นวิธีการทำงาน
DeadMG

2

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

ตัวอย่าง:

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

  • วัตถุที่มีชีวิตยืนยาวซึ่งยังคงถูกอ้างถึง แต่ไม่ได้ใช้อีกต่อไป (เนื่องจากตรรกะของโปรแกรม) แต่ที่ไม่ทำให้หน่วยความจำของคุณเติบโตขึ้น ตรวจสอบรหัสและพยายามค้นหาข้อบกพร่องอื่น ๆ ที่นำไปสู่ เพิ่มความคิดเห็นไปยังฐานของรหัสหากเป็นการปรับให้เหมาะสม (ประสิทธิภาพ) โดยเจตนา

  • วัตถุมีอายุยืน "โดยการออกแบบ" รูปแบบซิงเกิลตัวอย่าง พวกเขายากที่จะกำจัดโดยเฉพาะอย่างยิ่งหากเป็นแอพพลิเคชั่นแบบมัลติเธรด

  • วัตถุรีไซเคิล วัตถุที่มีชีวิตยืนยาวไม่จำเป็นต้องเลวร้ายเสมอไป พวกเขายังสามารถเป็นประโยชน์ แทนที่จะมีการจัดสรร / ยกเลิกการจัดสรรหน่วยความจำความถี่สูงการเพิ่มออบเจ็กต์ที่ไม่ได้ใช้ในปัจจุบันลงในคอนเทนเนอร์เพื่อดึงออกมาเมื่อจำเป็นต้องใช้บล็อกหน่วยความจำอีกครั้งสามารถช่วยเร่งแอปพลิเคชันและหลีกเลี่ยงการกระจายตัวของฮีป พวกเขาควรจะฟรีได้ง่ายในเวลาปิดเครื่องอาจอยู่ในโครงสร้าง "เครื่องมือ / ตรวจสอบแล้ว" เป็นพิเศษ

  • "วัตถุที่ใช้ร่วมกัน" - วัตถุที่มีการใช้ (อ้างอิง) โดยวัตถุอื่นหลายรายการและไม่มีใครรู้ว่าเมื่อมันถูกบันทึกเพื่อให้เป็นอิสระ ลองเปลี่ยนมันให้เป็นวัตถุที่มีการอ้างอิง

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


0

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

แนวคิดของ "หนี้ทางเทคนิค" คือเมื่อคุณใช้ทางลัดเช่นนี้เมื่อมีคนต้องการเปลี่ยนรหัสในอนาคต (สมมติว่าฉันต้องการทำให้ลูกค้าเข้าสู่โหมดออฟไลน์หรือโหมดสลีป "หรือฉันต้องการสลับเซิร์ฟเวอร์โดยไม่ต้องเริ่มกระบวนการใหม่) พวกเขาจะต้องใช้ความพยายามในการทำสิ่งที่คุณกำลังข้ามไป แต่พวกเขาจะรักษารหัสของคุณไว้ดังนั้นพวกเขาจะไม่รู้อะไรเกี่ยวกับมันมากเท่าที่คุณทำดังนั้นมันจะใช้เวลานานกว่านี้มาก (ฉันไม่ได้พูดถึงอีก 20% อีกต่อไปฉันกำลังพูดถึงอีก 20x!) แม้ว่าจะเป็นคุณ แต่คุณจะไม่ได้ทำงานกับรหัสนี้เป็นเวลาหลายสัปดาห์หรือหลายเดือนและจะใช้เวลานานกว่านั้นในการกำจัดใยแมงมุมออกเพื่อให้สามารถใช้งานได้อย่างถูกต้อง

ในกรณีนี้ดูเหมือนว่าคุณมีการเชื่อมต่อระหว่างวัตถุเซิร์ฟเวอร์กับวัตถุ "อายุการใช้งานที่ยาวนาน" ... มีหลายครั้งที่เรคคอร์ดสามารถ (และควร) อยู่ได้นานกว่าการเชื่อมต่อกับเซิร์ฟเวอร์ การบำรุงรักษาการเปลี่ยนแปลงทุกอย่างให้กับวัตถุในเซิร์ฟเวอร์นั้นอาจมีราคาแพงห้ามดังนั้นโดยปกติจะดีกว่าที่วัตถุที่เกิดใหม่จะถูกตรวจจับที่จับกับวัตถุเซิร์ฟเวอร์ด้วยการบันทึกและอัปเดตการโทรที่เปลี่ยนเซิร์ฟเวอร์จริง สิ่งนี้เรียกว่ารูปแบบการบันทึกที่ใช้งานอยู่ ดู:

http://en.wikipedia.org/wiki/Active_record_pattern

ใน C ++ ฉันมีเร็กคอร์ดที่แอ็คทีฟแต่ละตัวมีจุดอ่อนเพื่อเซิร์ฟเวอร์ซึ่งอาจทำให้เกิดสิ่งต่าง ๆ อย่างชาญฉลาดหากการเชื่อมต่อเซิร์ฟเวอร์มืด คลาสเหล่านี้สามารถเป็นแบบเกียจคร้านหรือแบบแบตช์ขึ้นอยู่กับความต้องการของคุณ แต่อายุการใช้งานของวัตถุเหล่านั้นควรเป็นตำแหน่งที่ใช้เท่านั้น

ดูสิ่งนี้ด้วย:

เป็นการเสียเวลาเปล่า ๆ กับการเพิ่มทรัพยากรก่อนที่ฉันจะออกจากกระบวนการหรือไม่?

อื่น ๆ


This reeks of global variablesคุณจะไปจาก "มีวัตถุนับพันที่ต้องได้รับการปลดปล่อย" เป็น "พวกเขาจะต้องเป็นโลก" นั่นเป็นเหตุผลที่ค่อนข้างก้าวกระโดด
Doval

0

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

ในกรณีที่คุณไม่คุ้นเคยกับแนวคิดต่อไปนี้เป็นบทความเกี่ยวกับวิธีการจัดสรรหน่วยความจำแบบกำหนดเองใน c ++แม้ว่าโปรดทราบว่าโซลูชันของคุณอาจจะง่ายกว่าตัวอย่างในบทความนั้นเนื่องจากคุณไม่จำเป็นต้องจัดการกับการลบเลย !

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.