การรั่วไหลทางกายภาพ
ชนิดของข้อบกพร่องที่ที่อยู่ของ GC ดูเหมือนจะ (อย่างน้อยก็ต่อผู้สังเกตการณ์ภายนอก) ซึ่งเป็นสิ่งที่โปรแกรมเมอร์ที่รู้ภาษาไลบรารีแนวคิดแนวความคิดและสำนวนอื่น ๆ แต่ฉันอาจผิด: การจัดการหน่วยความจำด้วยตนเองมีความซับซ้อนหรือไม่
มาจากปลาย C ซึ่งทำให้การจัดการหน่วยความจำเกี่ยวกับเป็นคู่มือและเด่นชัดที่สุดเพื่อให้เราเปรียบเทียบสุดขั้ว (C ++ ส่วนใหญ่ทำการจัดการหน่วยความจำโดยอัตโนมัติโดยไม่ต้อง GC) ฉันจะพูดว่า "ไม่จริง" ในแง่ของการเปรียบเทียบกับ GC เมื่อมัน มาถึงการรั่วไหล ผู้เริ่มต้นและบางครั้งก็เป็นมืออาชีพอาจจะลืมที่จะเขียนให้ได้รับfree
malloc
มันเกิดขึ้นอย่างแน่นอน
อย่างไรก็ตามมีเครื่องมือเช่นvalgrind
การตรวจจับการรั่วไหลซึ่งจะสังเกตเห็นได้ทันทีในการดำเนินการรหัสเมื่อ / ที่ไหนผิดพลาดดังกล่าวเกิดขึ้นกับสายของรหัสที่แน่นอน เมื่อรวมเข้ากับ CI มันแทบจะเป็นไปไม่ได้เลยที่จะรวมความผิดพลาดดังกล่าวเข้าด้วยกัน ดังนั้นจึงไม่เป็นเรื่องใหญ่สำหรับทีม / กระบวนการที่มีมาตรฐานที่สมเหตุสมผล
จริงอยู่ที่อาจมีบางกรณีที่แปลกใหม่ของการดำเนินการที่บินภายใต้เรดาร์ของการทดสอบที่free
ไม่สามารถเรียกได้ว่าอาจจะพบข้อผิดพลาดการป้อนข้อมูลภายนอกที่คลุมเครือเช่นไฟล์เสียหายในกรณีที่ระบบอาจรั่ว 32 ไบต์หรืออะไรบางอย่าง ฉันคิดว่ามันสามารถเกิดขึ้นได้อย่างแน่นอนแม้ภายใต้มาตรฐานการทดสอบที่ดีและเครื่องมือตรวจจับรอยรั่ว เราจะเห็นปัญหาที่ใหญ่กว่าซึ่งเราสามารถรั่วไหลของทรัพยากรขนาดใหญ่ได้แม้ในเส้นทางการดำเนินการทั่วไปด้านล่างในแบบที่ GC ไม่สามารถป้องกันได้
นอกจากนี้ยังเป็นเรื่องยากโดยไม่มีสิ่งใดที่คล้ายกับรูปแบบหลอกของ GC (การนับการอ้างอิงเช่น) เมื่ออายุการใช้งานของวัตถุต้องขยายออกไปสำหรับการประมวลผลแบบเลื่อน / อะซิงโครนัสในบางรูปแบบ
พอยน์เตอร์ชี้
ปัญหาจริงที่มีรูปแบบการจัดการหน่วยความจำแบบแมนนวลนั้นไม่รั่วไหลสำหรับฉัน มีแอปพลิเคชั่นที่เขียนด้วยภาษา C หรือ C ++ เป็นจำนวนเท่าใดที่ทราบว่ามีการรั่วไหลจริง ๆ เคอร์เนล Linux รั่วหรือไม่ MySQL? CryEngine 3 เวิร์คสเตชั่เสียงดิจิตอลและซินธิไซเซอร์? Java VM มีการรั่วไหลหรือไม่ (ใช้งานในรหัสเนทีฟ) Photoshop?
หากมีสิ่งใดฉันคิดว่าเมื่อเรามองไปรอบ ๆ แอปพลิเคชั่นที่เล็กที่สุดมักจะเป็นแอพที่เขียนขึ้นโดยใช้โครงร่าง GC แต่ก่อนที่จะถูกใช้เป็นสแลคในการรวบรวมขยะรหัสเนทีฟมีปัญหาสำคัญที่ไม่เกี่ยวข้องกับการรั่วไหลของหน่วยความจำเลย
ปัญหาสำหรับฉันคือความปลอดภัยเสมอ แม้ว่าเราจะfree
จำหน่วยความจำผ่านพอยน์เตอร์ได้หากมีพอยน์เตอร์อื่น ๆ เข้ากับรีซอร์สพอยน์เตอร์จะกลายเป็นพอยน์เตอร์
เมื่อเราพยายามเข้าถึงพอยท์เตอร์ของพอยน์เตอร์ที่ห้อยต่องแต่งเราจบลงด้วยพฤติกรรมที่ไม่ได้กำหนดแม้ว่าเกือบจะเป็นการละเมิด segfault / access ที่นำไปสู่ความผิดพลาดที่ยากและทันที
แอปพลิเคชั่นดั้งเดิมทั้งหมดที่ฉันระบุไว้ข้างต้นอาจมีเคสที่คลุมเครือหรือสองอย่างซึ่งอาจนำไปสู่ความผิดพลาดเป็นหลักเนื่องจากปัญหานี้และมีส่วนแบ่งการใช้งานแอพพลิเคชั่นต่ำมากที่เขียนด้วยโค้ดเนทีฟ ส่วนใหญ่เนื่องจากปัญหานี้
... และเป็นเพราะการจัดการทรัพยากรทำได้ยากไม่ว่าคุณจะใช้ GC หรือไม่ก็ตาม ความแตกต่างในทางปฏิบัติมักเกิดจากการรั่ว (GC) หรือการหยุดทำงาน (โดยไม่มี GC) เมื่อพบข้อผิดพลาดที่นำไปสู่การจัดการทรัพยากร
การจัดการทรัพยากร: การรวบรวมขยะ
การจัดการทรัพยากรที่ซับซ้อนนั้นยากกระบวนการด้วยตนเองไม่ว่าจะเกิดอะไรขึ้น GC ไม่สามารถทำอะไรที่นี่โดยอัตโนมัติ
ลองมาตัวอย่างที่เรามีวัตถุนี้ "โจ" Joe ถูกอ้างอิงโดยองค์กรจำนวนหนึ่งซึ่งเขาเป็นสมาชิก ทุก ๆ เดือนพวกเขาจะเก็บค่าธรรมเนียมสมาชิกจากบัตรเครดิตของเขา
นอกจากนี้เรายังมีการอ้างอิงถึงโจเพื่อควบคุมชีวิตของเขา สมมติว่าในฐานะโปรแกรมเมอร์เราไม่ต้องการโจอีกต่อไป เขาเริ่มที่จะรบกวนเราและเราไม่ต้องการองค์กรเหล่านี้อีกต่อไปที่เขาจะต้องเสียเวลากับเขา ดังนั้นเราจึงพยายามที่จะเช็ดเขาออกจากพื้นโลกโดยการลบการอ้างอิงเส้นชีวิตของเขา
... แต่เดี๋ยวก่อนเรากำลังใช้การรวบรวมขยะ การอ้างอิงที่แข็งแกร่งถึง Joe ทุกคนจะทำให้เขาอยู่ใกล้ ๆ ดังนั้นเราจึงลบการอ้างอิงถึงเขาออกจากองค์กรที่เขาเป็นสมาชิกอยู่ (ยกเลิกการสมัครสมาชิก)
... ยกเว้นอ๊ะเราลืมยกเลิกการสมัครสมาชิกนิตยสารของเขา! ตอนนี้โจยังอยู่ในความทรงจำรบกวนเราและใช้ทรัพยากรให้หมดไปและ บริษัท นิตยสารก็จบลงด้วยการดำเนินการเป็นสมาชิกของโจทุกเดือน
นี่เป็นข้อผิดพลาดหลักซึ่งอาจทำให้โปรแกรมที่ซับซ้อนจำนวนมากที่เขียนโดยใช้แผนการรวบรวมขยะเพื่อรั่วไหลและเริ่มใช้หน่วยความจำมากขึ้นเรื่อย ๆ ยิ่งทำงานนานขึ้นและอาจเกิดการประมวลผลมากขึ้น (การสมัครสมาชิกนิตยสารซ้ำ ๆ ) พวกเขาลืมที่จะลบการอ้างอิงเหล่านี้หนึ่งรายการขึ้นไปทำให้เป็นไปไม่ได้ที่นักสะสมขยะจะทำเวทย์มนตร์จนกว่าโปรแกรมทั้งหมดจะปิดตัวลง
อย่างไรก็ตามโปรแกรมก็ไม่ผิดพลาด มันปลอดภัยอย่างสมบูรณ์แบบ มันเป็นเพียงการเพิ่มความจำและ Joe จะยังคงวนเวียนอยู่ สำหรับแอปพลิเคชั่นจำนวนมากลักษณะการรั่วไหลแบบนี้ที่เราเพิ่งโยนหน่วยความจำ / การประมวลผลมากขึ้นและมากขึ้นอาจทำให้เกิดปัญหาฮาร์ดไดรฟ์โดยเฉพาะอย่างยิ่งเนื่องจากหน่วยความจำและกำลังประมวลผลที่เครื่องของเรามี
การจัดการทรัพยากร: คู่มือ
ทีนี้ลองพิจารณาทางเลือกที่เราใช้พอยน์เตอร์กับ Joe และการจัดการหน่วยความจำด้วยตนเองเช่น:
ลิงค์สีน้ำเงินเหล่านี้ไม่ได้จัดการอายุการใช้งานของโจ หากเราต้องการที่จะลบเขาออกจากพื้นดินเราขอทำลายด้วยตนเองเช่น:
ตอนนี้โดยปกติแล้วจะปล่อยให้เรามีพอยน์เตอร์ห้อยอยู่ทุกที่ดังนั้นขอลบพอยน์เตอร์ให้โจ
... อ๊ะเราทำผิดพลาดเหมือนเดิมอีกครั้งและลืมยกเลิกการสมัครสมาชิกนิตยสารของ Joe!
ยกเว้นตอนนี้เรามีตัวชี้ห้อย เมื่อการสมัครสมาชิกนิตยสารพยายามที่จะประมวลผลค่าบริการรายเดือนของ Joe ทั้งโลกจะระเบิด - โดยทั่วไปเราจะได้รับความผิดพลาดอย่างหนักทันที
ข้อผิดพลาดในการจัดการทรัพยากรพื้นฐานแบบเดียวกันนี้ซึ่งนักพัฒนาลืมที่จะลบพอยน์เตอร์ / การอ้างอิงไปยังทรัพยากรด้วยตนเองสามารถนำไปสู่การล่มจำนวนมากในแอปพลิเคชั่นดั้งเดิม พวกเขาไม่ได้ใช้หน่วยความจำนานกว่าปกติเพราะจะทำให้เกิดปัญหาในกรณีนี้
โลกแห่งความจริง
ตอนนี้ตัวอย่างข้างต้นคือการใช้ไดอะแกรมอย่างง่ายที่น่าขัน แอปพลิเคชันในโลกแห่งความเป็นจริงอาจต้องใช้รูปภาพหลายพันภาพต่อกันเพื่อให้ครอบคลุมกราฟเต็มรูปแบบโดยมีทรัพยากรหลายร้อยชนิดที่เก็บไว้ในกราฟฉากทรัพยากร GPU ที่เกี่ยวข้องกับบางส่วนของพวกเขา การดูจำนวนเอนทิตีในฉากสำหรับการเปลี่ยนแปลงผู้สังเกตการณ์สังเกตผู้สังเกตการณ์ไฟล์เสียงที่ซิงค์กับภาพเคลื่อนไหว ฯลฯ ดังนั้นมันอาจดูเหมือนง่ายที่จะหลีกเลี่ยงความผิดพลาดที่ฉันได้อธิบายไว้ข้างต้น แต่โดยทั่วไปแล้วมันไม่มีที่ไหนเลย การผลิต codebase สำหรับแอพพลิเคชั่นที่ซับซ้อนซึ่งครอบคลุมโค้ดหลายล้านบรรทัด
โอกาสที่บางคนในวันหนึ่งจะจัดการทรัพยากรที่ผิดพลาดในที่อื่น ๆ ในโค๊ดเบสนั้นมีแนวโน้มที่จะสูงและความน่าจะเป็นนั้นจะเป็นแบบเดียวกันโดยมีหรือไม่มี GC ความแตกต่างที่สำคัญคือสิ่งที่จะเกิดขึ้นอันเป็นผลมาจากความผิดพลาดนี้ซึ่งอาจส่งผลกระทบต่อความผิดพลาดนี้จะถูกระบุและแก้ไขอย่างรวดเร็ว
Crash vs. Leak
ตอนนี้อันไหนแย่กว่ากัน? เกิดความผิดพลาดขึ้นทันทีหรือหน่วยความจำเงียบเงียบที่โจเพียงแค่ก้องกังวาน?
ส่วนใหญ่อาจตอบกลับ แต่สมมติว่าซอฟต์แวร์นี้ออกแบบมาเพื่อให้ทำงานได้นานหลายชั่วโมงอาจเป็นวันและแต่ละวันของ Joe และ Jane ที่เราเพิ่มจะเพิ่มการใช้หน่วยความจำของซอฟต์แวร์ด้วยกิกะไบต์ ไม่ใช่ซอฟต์แวร์ที่มีความสำคัญต่อภารกิจ (เกิดปัญหาไม่ได้ฆ่าผู้ใช้จริง ๆ ) แต่เป็นซอฟต์แวร์ที่มีความสำคัญต่อประสิทธิภาพ
ในกรณีนี้ฮาร์ดไดรฟ์ที่ปรากฏขึ้นทันทีเมื่อทำการดีบั๊กชี้ให้เห็นข้อผิดพลาดที่คุณทำอาจเป็นที่นิยมมากกว่าซอฟต์แวร์ที่รั่วซึ่งอาจลอยอยู่ใต้เรดาร์ของกระบวนการทดสอบของคุณ
ในทางกลับกันหากเป็นซอฟต์แวร์ที่มีความสำคัญต่อภารกิจซึ่งประสิทธิภาพไม่ใช่เป้าหมาย แต่ไม่ล้มเหลวด้วยวิธีการใด ๆ ที่เป็นไปได้การรั่วไหลอาจเป็นที่นิยมมากกว่า
ข้อมูลอ้างอิงที่อ่อนแอ
มีความหลากหลายของความคิดเหล่านี้ที่มีอยู่ในโครงร่าง GC ที่รู้จักกันว่าการอ้างอิงที่อ่อนแอ ด้วยการอ้างอิงที่ไม่รัดกุมเราสามารถให้องค์กรเหล่านี้อ่อนแอ - อ้างอิง Joe แต่ไม่ป้องกันเขาจากการถูกลบเมื่อการอ้างอิงที่แข็งแกร่ง (เจ้าของ / เส้นชีวิตของ Joe) หายไป อย่างไรก็ตามเราได้รับประโยชน์จากความสามารถในการตรวจจับเมื่อโจไม่ได้อยู่ในการอ้างอิงที่อ่อนแอเหล่านี้อีกต่อไปทำให้เราได้รับข้อผิดพลาดที่ทำซ้ำได้อย่างง่ายดาย
น่าเสียดายที่การอ้างอิงที่อ่อนแอนั้นไม่ได้ใช้งานเกือบเท่าที่ควรจะใช้ดังนั้นบ่อยครั้งที่แอปพลิเคชัน GC ที่ซับซ้อนจำนวนมากอาจมีความเสี่ยงต่อการรั่วไหลแม้ว่าจะมีความผิดพลาดน้อยกว่าแอปพลิเคชัน C ที่ซับซ้อนเช่น
ไม่ว่าในกรณีใด GC จะทำให้ชีวิตของคุณง่ายขึ้นหรือยากขึ้นอยู่กับว่าซอฟต์แวร์ของคุณมีความสำคัญต่อการหลีกเลี่ยงการรั่วไหลหรือไม่และเกี่ยวข้องกับการจัดการทรัพยากรที่ซับซ้อนของประเภทนี้หรือไม่
ในกรณีของฉันฉันทำงานในฟิลด์ประสิทธิภาพที่สำคัญซึ่งทรัพยากรครอบคลุมหลายร้อยเมกะไบต์เป็นกิกะไบต์และไม่ปล่อยหน่วยความจำนั้นเมื่อผู้ใช้ร้องขอให้ยกเลิกการโหลดเนื่องจากความผิดพลาดเช่นด้านบนอาจเป็นที่นิยมน้อยกว่าความผิดพลาด ความผิดพลาดนั้นง่ายต่อการตรวจจับและทำให้เกิดซ้ำทำให้พวกมันมักจะเป็นข้อผิดพลาดที่ชื่นชอบของโปรแกรมเมอร์แม้ว่ามันจะเป็นสิ่งที่ผู้ใช้ชื่นชอบน้อยที่สุดและความผิดพลาดเหล่านี้จำนวนมากก็จะปรากฏขึ้น
อย่างไรก็ตามความแตกต่างระหว่าง GC และการจัดการหน่วยความจำด้วยตนเองคือ เพื่อตอบคำถามของคุณฉันจะบอกว่าการจัดการหน่วยความจำด้วยตนเองนั้นทำได้ยาก แต่มีน้อยมากที่จะเกิดการรั่วไหลและ GC และรูปแบบการจัดการหน่วยความจำแบบแมนนวลก็ยังคงทำได้ยากมากเมื่อการจัดการทรัพยากรไม่มีความสำคัญ เนื้อหา GC มีพฤติกรรมที่ยุ่งยากมากขึ้นที่นี่ซึ่งโปรแกรมดูเหมือนว่าจะทำงานได้ดี แต่ใช้ทรัพยากรมากขึ้นเรื่อย ๆ แบบฟอร์มด้วยตนเองนั้นมีความยุ่งยากน้อยกว่า แต่จะผิดพลาดและเผาครั้งใหญ่โดยมีข้อผิดพลาดเหมือนกับที่แสดงด้านบน