เหตุใด C ++ จึงไม่มีตัวรวบรวมขยะ


270

ฉันไม่ได้ถามคำถามนี้เพราะข้อดีของการเก็บขยะก่อนอื่น เหตุผลหลักของฉันในการถามนี้คือฉันรู้ว่า Bjarne Stroustrup บอกว่า C ++ จะมีตัวรวบรวมขยะในบางเวลา

พร้อมที่กล่าวว่าทำไมมันไม่ได้ถูกเพิ่มเข้ามา? มีนักสะสมขยะสำหรับ C ++ อยู่แล้ว นี่เป็นเพียงหนึ่งในประเภทที่ "พูดง่ายกว่าทำ" หรือมีเหตุผลอื่น ๆ ที่ยังไม่ถูกเพิ่ม (และจะไม่ถูกเพิ่มใน C ++ 11)?

ลิงก์ข้าม:

เพื่อชี้แจงฉันเข้าใจเหตุผลที่ C ++ ไม่มีตัวรวบรวมขยะเมื่อสร้างครั้งแรก ฉันสงสัยว่าทำไมไม่สามารถเพิ่มนักสะสม


26
นี่เป็นหนึ่งในสิบอันดับเทพนิยายเกี่ยวกับ C ++ ที่ผู้เกลียดชังมักจะนำขึ้นมา การรวบรวมขยะไม่ใช่ "การสร้าง" แต่มีวิธีง่าย ๆ ในการทำ C ++ การโพสต์แสดงความคิดเห็นเพราะคนอื่น ๆ มีคำตอบอยู่แล้วดีกว่าที่ฉันสามารถทำได้ดังต่อไปนี้ :)
davr

5
แต่นั่นเป็นจุดรวมของการไม่ได้อยู่ในตัวคุณต้องทำด้วยตัวเอง ความเป็นจริงจากสูงไปต่ำ: ในตัว, ไลบรารี, ทำที่บ้าน ฉันใช้ C ++ ด้วยตัวเองและไม่เกลียดใครเพราะเป็นภาษาที่ดีที่สุดในโลก แต่การจัดการหน่วยความจำแบบไดนามิกเป็นความเจ็บปวด
QBziZ

4
@Davr - ฉันไม่ใช่ผู้เกลียดชัง C ++ และฉันก็ยังพยายามที่จะเถียงว่า C ++ ต้องการตัวเก็บรวบรวมขยะ ฉันถามเพราะฉันรู้ว่า Bjarne Stroustrup บอกว่ามันจะถูกเพิ่มเข้ามาและก็แค่อยากรู้ว่าเหตุผลในการไม่ใช้งานมันคืออะไร
Jason Baker

1
บทความนี้ตัวเก็บรวบรวม Boehm สำหรับ C และ C ++ จาก Dr. Dobbsอธิบายตัวรวบรวมขยะโอเพนซอร์สที่สามารถใช้ได้กับทั้ง C และ C ++ มันกล่าวถึงปัญหาบางอย่างที่เกิดขึ้นกับการใช้ตัวรวบรวมขยะกับ C ++ destructors เช่นเดียวกับ C Standard Library
Richard Chambers

1
@rogerdpack: แต่ตอนนี้ยังไม่เป็นประโยชน์ (ดูคำตอบของฉัน ... ) ดังนั้นการติดตั้งใช้งานที่ไม่น่าจะเกิดขึ้นได้หากลงทุน
einpoklum

คำตอบ:


160

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

คำพูดจาก Bjarne Stroustrup ตัวเอง:

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

มีการอภิปรายที่ดีของหัวข้อเป็นที่นี่

ภาพรวมทั่วไป:

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

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

การรวบรวมขยะมี 2 ประเภท ...

การรวบรวมขยะอย่างชัดเจน:

C ++ 0x จะมีการรวบรวมขยะผ่านพอยน์เตอร์ที่สร้างขึ้นด้วย shared_ptr

หากคุณต้องการคุณสามารถใช้มันได้หากคุณไม่ต้องการคุณจะไม่ถูกบังคับให้ใช้งาน

ขณะนี้คุณสามารถใช้การเพิ่ม: shared_ptr ได้เช่นกันหากคุณไม่ต้องการรอ C ++ 0x

การรวบรวมขยะโดยนัย:

มันไม่มีการรวบรวมขยะโปร่งใสแม้ว่า มันจะเป็นจุดโฟกัสสำหรับสเปค C ++ ในอนาคต

ทำไม Tr1 ไม่มีการเก็บขยะโดยปริยาย

มีหลายสิ่งที่ tr1 ของ C ++ 0x น่าจะมี Bjarne Stroustrup ในการสัมภาษณ์ครั้งก่อนระบุว่า tr1 ไม่ได้มากเท่าที่เขาจะชอบ


71
ฉันจะกลายเป็นผู้เกลียดชังถ้า C ++ บังคับให้ฉันเก็บขยะ! ทำไมคนไม่สามารถใช้smart_ptr's? คุณจะทำฟอร์กยูนิกซ์ระดับต่ำในระดับต่ำอย่างไร สิ่งอื่น ๆ จะได้รับผลกระทบเช่นการทำเกลียว Python มีการล็อคล่ามระดับโลกเป็นส่วนใหญ่เนื่องจากเป็นชุดรวบรวมขยะ (ดู Cython) เก็บไว้ใน C / C ++ ขอบคุณ
unixman83

26
@ unixman83: ปัญหาหลักของการอ้างอิงการเก็บรวบรวมขยะ (เช่นstd::shared_ptr) คือการอ้างอิงตามวัฏจักรซึ่งทำให้หน่วยความจำรั่ว ดังนั้นคุณต้องใช้อย่างรอบคอบstd::weak_ptrเพื่อทำลายวงจรซึ่งยุ่ง สไตล์การทำเครื่องหมายและการกวาด GC ไม่มีปัญหานี้ ไม่มีความเข้ากันไม่ได้โดยธรรมชาติระหว่างเธรด / ฟอร์กและการรวบรวมขยะ Java และ C # ทั้งคู่มีประสิทธิภาพสูงในการมัลติเธรดแบบ preemptive และและตัวรวบรวมขยะ มีปัญหาเกี่ยวกับแอปพลิเคชันเรียลไทม์และตัวรวบรวมขยะเนื่องจากนักสะสมขยะส่วนใหญ่ต้องหยุดโลกให้ทำงาน
Andrew Tomazos

9
"ปัญหาหลักที่มีการอ้างอิงการเก็บขยะนับ (เช่นstd::shared_ptr) คือการอ้างอิงตามวัฏจักร" และประสิทธิภาพอันยิ่งใหญ่ซึ่งเป็นเรื่องน่าขันเพราะประสิทธิภาพที่ดีกว่ามักเป็นข้ออ้างสำหรับการใช้ C ++ ... flyingfrogblog.blogspot.co.uk/2011/01/…
Jon Harrop

11
คุณจะทำฟอร์กยูนิกซ์ระดับต่ำได้อย่างไร ". วิธีเดียวกับที่ GC'd ใช้ภาษาอย่าง OCaml ทำมาแล้วประมาณ 20 ปีขึ้นไป
Jon Harrop

9
"Python มีการล็อคล่ามระดับโลกเป็นส่วนใหญ่เพราะเป็นชุดเก็บขยะ" อาร์กิวเมนต์ Strawman Java และ. NET ทั้งคู่มี GCs แต่ไม่มีการล็อคระดับโลก
Jon Harrop

149

เพื่อเพิ่มการอภิปรายที่นี่

มีปัญหาที่ทราบเกี่ยวกับการรวบรวมขยะและการทำความเข้าใจช่วยให้เข้าใจว่าทำไมไม่มีใน C ++

1. ประสิทธิภาพ?

การร้องเรียนครั้งแรกมักจะเกี่ยวกับประสิทธิภาพ แต่คนส่วนใหญ่ไม่ได้ตระหนักถึงสิ่งที่พวกเขากำลังพูดถึง ตามที่แสดงโดยMartin Beckettปัญหาอาจไม่ได้ประสิทธิภาพต่อ se แต่เป็นการคาดการณ์ของประสิทธิภาพ

ปัจจุบันมีตระกูล GC 2 ตระกูลที่ปรับใช้อย่างกว้างขวาง:

  • ประเภท Mark-And-Sweep
  • ชนิดการอ้างอิงการอ้างอิง

Mark And Sweepเร็ว (ผลกระทบน้อยลงในการปฏิบัติงานโดยรวม) แต่มันทนทุกข์ทรมานจาก "หยุดโลก" ซินโดรม: คือเมื่อได้ลูกเตะ GC ในทุกอย่างอื่นจะหยุดการทำงานจนกว่า GC ได้ทำให้การทำความสะอาดของ หากคุณต้องการสร้างเซิร์ฟเวอร์ที่ตอบสนองในไม่กี่มิลลิวินาที ... ธุรกรรมบางอย่างจะไม่เป็นไปตามที่คุณคาดหวัง :)

ปัญหาที่Reference Countingแตกต่าง: การนับการอ้างอิงเพิ่มค่าใช้จ่ายโดยเฉพาะอย่างยิ่งในสภาพแวดล้อม Multi-Threading เพราะคุณต้องมีการนับอะตอม นอกจากนี้ยังมีปัญหาของรอบการอ้างอิงดังนั้นคุณต้องใช้อัลกอริทึมที่ฉลาดในการตรวจสอบรอบเหล่านั้นและกำจัดพวกมัน (โดยทั่วไปจะใช้โดย "แช่แข็งโลก" ด้วยเช่นกัน แต่บ่อยครั้งน้อยกว่า) โดยทั่วไปแล้ว ณ วันนี้ประเภทนี้ (แม้ว่าตามปกติมากขึ้นการตอบสนองหรือค่อนข้างน้อยมักจะแช่แข็ง) Mark And Sweepจะช้ากว่า

ฉันเคยเห็นกระดาษจากผู้ดำเนินการของไอเฟลที่พยายามใช้งานReference CountingGarbage Collector ซึ่งจะมีประสิทธิภาพระดับโลกที่คล้ายคลึงกันMark And Sweepโดยไม่ต้องมี "แช่แข็งโลก" มันต้องการเธรดแยกต่างหากสำหรับ GC (ทั่วไป) อัลกอริทึมนั้นค่อนข้างน่ากลัว (ในตอนท้าย) แต่กระดาษก็ทำหน้าที่ได้ดีในการนำแนวคิดหนึ่งครั้งและแสดงวิวัฒนาการของอัลกอริทึมจากเวอร์ชั่น "ง่าย" ไปจนถึงเวอร์ชันเต็ม แนะนำให้อ่านถ้าฉันสามารถวางมือบนไฟล์ PDF ...

2. การจัดหาทรัพยากรเป็นการเริ่มต้น (RAII)

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

  • ล็อค (หลายเธรดจัดการไฟล์ ... )
  • การเชื่อมต่อ (ไปยังฐานข้อมูลเซิร์ฟเวอร์อื่น ... )

แนวคิดคือการควบคุมอายุการใช้งานของวัตถุอย่างถูกต้อง:

  • มันควรจะมีชีวิตอยู่ตราบเท่าที่คุณต้องการ
  • มันควรจะถูกฆ่าตายเมื่อคุณทำเสร็จแล้ว

ปัญหาของ GC คือถ้ามันช่วยได้กับอดีตและในที่สุดก็รับประกันได้ว่าในภายหลัง ... "สุดยอด" นี้อาจไม่เพียงพอ หากคุณปล่อยล็อคคุณต้องการให้มันปลดล็อคในขณะนี้เพื่อที่จะไม่ได้บล็อคการโทรเพิ่มเติม!

ภาษาที่มี GC มีสองวิธีแก้ไข:

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

3. พอยน์เตอร์อัจฉริยะ

ชี้สมาร์ทมักจะปรากฏเป็น bullet C++เงินกับหน่วยความจำในการจัดการ บ่อยครั้งที่ฉันได้ยิน: เราไม่ต้องการ GC เพราะเรามีพอยน์เตอร์อัจฉริยะ

หนึ่งอาจไม่ผิดมากขึ้น

ตัวชี้สมาร์ทช่วยauto_ptrและunique_ptrใช้แนวคิด RAII ซึ่งมีประโยชน์อย่างยิ่ง มันง่ายมากที่คุณสามารถเขียนมันเองได้ง่ายๆ

เมื่อต้องการแชร์ความเป็นเจ้าของ แต่มันก็ยากขึ้น: คุณอาจแชร์หลายเธรดและมีปัญหาเล็กน้อยบางประการเกี่ยวกับการจัดการการนับ shared_ptrดังนั้นหนึ่งตามธรรมชาติไปสู่การ

มันยอดเยี่ยมนั่นคือสิ่งที่ Boost for after แต่ไม่ใช่ bullet เงิน ในความเป็นจริงปัญหาหลักของshared_ptrมันคือมันเลียนแบบ GC ที่นำมาใช้Reference Countingแต่คุณต้องใช้การตรวจจับรอบทั้งหมดด้วยตัวเอง ... Urg

แน่นอนว่ามีสิ่งนี้weak_ptrแต่ฉันโชคไม่ดีที่ได้เห็นการรั่วไหลของหน่วยความจำแม้จะมีการใช้shared_ptrเพราะรอบเหล่านั้น ... และเมื่อคุณอยู่ในสภาพแวดล้อมแบบมัลติเธรดมันยากที่จะตรวจจับ!

4. อะไรคือทางออก?

ไม่มีกระสุนสีเงิน แต่ก็เป็นไปได้อย่างแน่นอน ในกรณีที่ไม่มี GC หนึ่งจะต้องชัดเจนในการเป็นเจ้าของ:

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

ดังนั้นจะเป็นการดีถ้ามี GC ... แต่มันไม่มีปัญหาเล็กน้อย และในเวลานั้นเราแค่ต้องพับแขนเสื้อของเรา


2
ฉันหวังว่าฉันจะยอมรับสองคำตอบ! นี่ยอดเยี่ยมมาก สิ่งหนึ่งที่ชี้ให้เห็นถึงประสิทธิภาพการทำงาน GC ที่ทำงานในเธรดแยกต่างหากนั้นเป็นเรื่องธรรมดาทั่วไป (ใช้ใน Java และ. Net) จริงอยู่ที่อาจไม่เป็นที่ยอมรับในระบบฝังตัว
Jason Baker

14
มีเพียงสองประเภทเท่านั้น? การคัดลอกนักสะสมเป็นอย่างไร นักสะสมรุ่น? นักสะสมที่เกิดขึ้นพร้อมกัน (รวมถึงลู่วิ่งไฟฟ้าแบบเรียลไทม์ของ Baker) นักสะสมลูกผสมหลายคน? ผู้ชายความไม่รู้ที่แท้จริงในอุตสาหกรรมของสาขานี้ทำให้ฉันประหลาดใจบางครั้ง
เพียงความคิดเห็นที่ถูกต้องของฉัน

12
ฉันบอกว่ามีแค่ 2 ประเภทเท่านั้น? ฉันบอกว่ามี 2 ตัวที่ใช้งานกันอย่างแพร่หลาย เท่าที่ฉันรู้ Python, Java และ C # ทั้งหมดใช้อัลกอริทึม Mark and Sweep ตอนนี้ (Java เคยมีอัลกอริทึมการนับอ้างอิง) เพื่อความแม่นยำมากขึ้นดูเหมือนว่าฉันกว่า C # ใช้ Generational GC สำหรับรอบรอง, Mark And Sweep สำหรับรอบที่สำคัญและการคัดลอกเพื่อต่อสู้กับการกระจายตัวของหน่วยความจำ; แม้ว่าฉันจะยืนยันว่าหัวใจของอัลกอริทึมคือ Mark And Sweep คุณรู้จักภาษากระแสหลักที่ใช้เทคโนโลยีอื่นหรือไม่? ฉันมีความสุขเสมอที่จะเรียนรู้
Matthieu M.

3
คุณเพิ่งตั้งชื่อภาษากระแสหลักหนึ่งภาษาที่ใช้สามภาษา
เพียงแค่ความคิดเห็นที่ถูกต้องของฉัน

3
ความแตกต่างที่สำคัญคือ Generational และ Incremental GC ไม่จำเป็นต้องหยุดโลกให้ทำงานและคุณสามารถทำให้มันทำงานบนระบบที่มีเธรดเดียวโดยไม่มีค่าใช้จ่ายมากเกินไปโดยการทำซ้ำของ traversal ต้นไม้เป็นครั้งคราวเมื่อเข้าถึงตัวชี้ GC (ปัจจัย) สามารถกำหนดได้โดยจำนวนโหนดใหม่พร้อมกับการคาดการณ์พื้นฐานของความต้องการในการรวบรวม) คุณสามารถเพิ่ม GC ได้มากขึ้นโดยการรวมข้อมูลเกี่ยวกับตำแหน่งที่เกิดโค้ดในการสร้าง / แก้ไขโหนดซึ่งอาจทำให้คุณสามารถปรับปรุงการทำนายของคุณและคุณจะได้รับ Escape Analysis ฟรี
Keldon Alleyne

56

ชนิดไหน? มันควรจะเหมาะสำหรับตัวควบคุมเครื่องซักผ้าฝังตัวโทรศัพท์มือถือเวิร์กสเตชันหรือซูเปอร์คอมพิวเตอร์?
มันควรจัดลำดับความสำคัญการตอบสนอง Gui หรือเซิร์ฟเวอร์โหลด?
มันควรจะใช้หน่วยความจำหรือ CPU มากมาย

C / c ++ ใช้ในสถานการณ์ที่แตกต่างกันมากเกินไป ฉันสงสัยว่าบางอย่างเช่นการเพิ่มพอยน์เตอร์อัจฉริยะจะเพียงพอสำหรับผู้ใช้ส่วนใหญ่

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


6
ฉันเห็นจุดของคุณแน่นอน แต่ฉันรู้สึกอยากถามว่า: Java ไม่ได้ใช้กับแอพพลิเคชั่นมากมาย
เจสันเบเกอร์

35
ไม่จาวาไม่เหมาะสำหรับแอปพลิเคชั่นที่มีประสิทธิภาพสูงด้วยเหตุผลง่ายๆที่ไม่รับประกันประสิทธิภาพในระดับเดียวกับ C ++ ดังนั้นคุณจะพบมันในโทรศัพท์มือถือ แต่คุณจะไม่พบมันในเซลล์สวิตช์หรือซูเปอร์คอมพิวเตอร์
Zathrus

11
คุณสามารถซื้อเซิร์ฟเวอร์เพิ่มได้เสมอ แต่คุณไม่สามารถซื้อ CPU เพิ่มเติมสำหรับโทรศัพท์มือถือที่มีอยู่แล้วในกระเป๋าของลูกค้า!
Crashworks

8
Java ได้ทำ catchup ประสิทธิภาพจำนวนมากในประสิทธิภาพของ CPU ปัญหาที่ดื้อรั้นจริงๆคือการใช้หน่วยความจำ Java มีหน่วยความจำที่มีประสิทธิภาพน้อยกว่า C ++ และความไร้ประสิทธิภาพนั้นเกิดจากความจริงที่ว่ามันเก็บขยะ การรวบรวมขยะไม่สามารถทำได้อย่างรวดเร็วและมีประสิทธิภาพในหน่วยความจำซึ่งเป็นข้อเท็จจริงที่เห็นได้ชัดหากคุณพิจารณาว่า GC ทำงานอย่างไร
Nate CK

2
@Zathrus java สามารถชนะ throughput b / c ของการเพิ่มประสิทธิภาพ jit แต่ไม่ใช่ latency (boo เรียลไทม์) และแน่นอนไม่ใช่ footprint ของหน่วยความจำ
gtrak

34

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

  • อายุการใช้งานที่กำหนดของวัตถุ (การนับการอ้างอิงจะให้สิ่งนี้แก่คุณ แต่ GC ไม่ได้แม้ว่ามันอาจจะไม่ใช่เรื่องใหญ่ก็ตาม)
  • จะเกิดอะไรขึ้นถ้า destructor ขว้างเมื่อวัตถุถูกเก็บขยะ? ภาษาส่วนใหญ่ไม่สนใจข้อยกเว้นนี้เนื่องจากไม่มีการบล็อก catch เพื่อให้สามารถส่งไปได้ แต่นี่อาจไม่ใช่ทางออกที่ยอมรับได้สำหรับ C ++
  • จะเปิด / ปิดการใช้งานได้อย่างไร โดยธรรมชาติแล้วอาจเป็นการตัดสินใจเวลารวบรวม แต่โค้ดที่เขียนขึ้นสำหรับ GC กับรหัสที่เขียนขึ้นสำหรับ NOT GC จะแตกต่างกันมากและอาจเข้ากันไม่ได้ คุณตกลงกันได้อย่างไร

ปัญหาเหล่านี้เป็นเพียงปัญหาเล็กน้อยเท่านั้น


17
GC และ destructors เป็นปัญหาที่แก้ไขได้โดยการหลีกเลี่ยงจาก Bjarne Destructors ไม่ทำงานระหว่าง GC เพราะนั่นไม่ใช่จุดของ GC GC ใน C ++ มีอยู่เพื่อสร้างแนวคิดของหน่วยความจำที่ไม่มีที่สิ้นสุดไม่ใช่ทรัพยากรอื่น ๆ ที่ไม่มีที่สิ้นสุด
MSalters

2
หาก destructors ไม่ทำงานที่เปลี่ยนความหมายของภาษาทั้งหมด ฉันเดาว่าอย่างน้อยที่สุดคุณจะต้องมีคำหลักใหม่ "gcnew" หรืออะไรบางอย่างเพื่อให้คุณอนุญาตให้วัตถุนี้เป็น GC'ed อย่างชัดเจน (ดังนั้นคุณไม่ควรใช้มันเพื่อห่อทรัพยากรที่อยู่นอกเหนือหน่วยความจำ)
Greg Rogers

7
นี่คืออาร์กิวเมนต์ปลอม เนื่องจาก C ++ มีการจัดการหน่วยความจำอย่างชัดเจนคุณต้องเข้าใจว่าเมื่อใดที่วัตถุทุกชิ้นต้องถูกปล่อยให้เป็นอิสระ ด้วย GC จะไม่เลวร้ายยิ่ง ค่อนข้างจะลดปัญหาที่จะหาเมื่อวัตถุบางอย่างเป็นอิสระคือวัตถุที่ต้องพิจารณาเป็นพิเศษในการลบ การโปรแกรมประสบการณ์ใน Java และ C # พบว่าวัตถุส่วนใหญ่ไม่จำเป็นต้องพิจารณาเป็นพิเศษและสามารถทิ้งไว้ที่ GC อย่างปลอดภัย เมื่อปรากฎว่าหนึ่งในฟังก์ชั่นหลักของ destructors ใน C ++ คือการปล่อยวัตถุลูกซึ่ง GC จัดการให้คุณโดยอัตโนมัติ
Nate CK

2
@ NateC-K: สิ่งหนึ่งที่ได้รับการปรับปรุงใน GC เทียบกับ non-GC (อาจจะเป็นสิ่งที่ใหญ่ที่สุด) คือความสามารถของระบบ GC ที่มั่นคงในการรับประกันว่าการอ้างอิงทุกครั้งจะยังคงชี้ไปที่วัตถุเดียวกันตราบใดที่มีการอ้างอิงอยู่ การเรียกDisposeใช้วัตถุอาจทำให้ไม่สามารถใช้งานได้ แต่การอ้างอิงที่ชี้ไปยังวัตถุเมื่อมันยังมีชีวิตอยู่จะยังคงทำเช่นนั้นหลังจากที่มันตาย ในทางตรงกันข้ามในระบบที่ไม่ใช่ GC จะสามารถลบวัตถุได้ในขณะที่มีการอ้างอิงอยู่และแทบจะไม่มีข้อ จำกัด ใด ๆ เกี่ยวกับความเสียหายที่อาจเกิดขึ้นหากมีการอ้างอิงอย่างใดอย่างหนึ่ง
supercat

22

แม้ว่านี่จะเป็นคำถามเก่าแต่ก็ยังมีปัญหาหนึ่งที่ฉันไม่เห็นใครพูดถึงเลย: การรวบรวมขยะแทบเป็นไปไม่ได้ที่จะระบุ

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

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

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

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

ถึงกระนั้นก็ดีกว่าสิ่งที่เสนอสำหรับ C ++ ข้อเสนอก่อนหน้านี้ [คำเตือน: PDF] (ที่ได้ลดลง) ไม่ได้อะไรรับประกันได้ทั้งหมด ใน 28 หน้าของข้อเสนอสิ่งที่คุณได้รับจากพฤติกรรมที่สังเกตได้จากภายนอกคือโน้ตตัวหนึ่ง (ไม่ใช่กฎเกณฑ์) ที่กล่าวว่า:

[หมายเหตุ: สำหรับโปรแกรมที่รวบรวมขยะการใช้งานโฮสต์คุณภาพสูงควรพยายามเพิ่มจำนวนหน่วยความจำที่ไม่สามารถเข้าถึงได้สูงสุดที่จะเรียกคืนได้ - บันทึกย่อ]

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

สิ่งที่ดีที่สุดที่เราได้รับคือโปรแกรมที่อาจใช้หน่วยความจำมากกว่าหกเท่าในการทดสอบด้วยจาวาตามการทดสอบกับ Java แย่กว่านั้นการรวบรวมขยะเป็นส่วนหนึ่งของ Java ตั้งแต่ต้น - C ++ มีข้อ จำกัด เพิ่มเติมเกี่ยวกับตัวรวบรวมขยะที่แน่นอนว่ามันจะมีอัตราส่วนราคาต่อผลประโยชน์ที่แย่ลง (แม้ว่าเราจะไปไกลกว่าข้อเสนอรับประกันและถือว่ามี ประโยชน์บางอย่าง)

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


ฉันจะวางตัวว่าแม้ว่าใครจะระบุว่าสำหรับการดำเนินการที่เหมาะสมวัตถุทั้งหมดจะต้องถูกลบและวัตถุที่ถูกลบจะมีสิทธิ์ได้รับการเก็บรวบรวมการสนับสนุนคอมไพเลอร์สำหรับการอ้างอิงการติดตามขยะอาจยังมีประโยชน์เนื่องจากภาษาดังกล่าวสามารถมั่นใจได้ การใช้ตัวชี้ที่ถูกลบ (การอ้างอิง) จะรับประกันว่าจะดักจับแทนที่จะทำให้เกิดพฤติกรรมที่ไม่ได้กำหนด
supercat

2
แม้ใน Java, GC ไม่ได้ระบุว่าจะทำอะไรที่เป็นประโยชน์ AFAIK จริงๆ มันอาจจะเรียกfreeคุณ (ซึ่งฉันหมายถึงภาษาอะนาfreeล็อกกับภาษา C) แต่ Java ไม่เคยรับประกันว่าจะเรียกผู้เข้ารอบสุดท้ายหรืออะไรทำนองนั้น ในความเป็นจริง C ++ ทำมากกว่า Java เพื่อรันการเขียนฐานข้อมูลการล้างข้อมูลการจัดการไฟล์และอื่น ๆ Java อ้างว่ามี "GC" แต่ผู้พัฒนา Java ต้องโทรอย่างพิถีพิถันclose()ตลอดเวลาและพวกเขาจะต้องตระหนักถึงการจัดการทรัพยากรอย่างระมัดระวังไม่ให้โทรclose()ช้าหรือช้าเกินไป C ++ ปลดปล่อยเราจากสิ่งนั้น ... (ต่อ)
Aaron McDaid

2
.. ความคิดเห็นของฉันสักครู่ที่ผ่านมาไม่ได้มีวัตถุประสงค์เพื่อวิพากษ์วิจารณ์ Java ฉันแค่สังเกตว่าคำว่า "การเก็บขยะ" เป็นคำที่แปลกมาก - มันมีความหมายน้อยกว่าที่ผู้คนคิดและมันจึงเป็นการยากที่จะพูดคุยกันโดยที่ไม่ชัดเจน
Aaron McDaid

@AaronMcDaid เป็นเรื่องจริงที่ GC ไม่ได้ช่วยเหลือทรัพยากรที่ไม่ใช่หน่วยความจำเลย โชคดีที่ทรัพยากรดังกล่าวได้รับการจัดสรรค่อนข้างน้อยเมื่อเทียบกับหน่วยความจำ ยิ่งกว่านั้น 90% ของพวกเขาสามารถเป็นอิสระในวิธีการที่จัดสรรพวกเขาดังนั้นจึงtry (Whatever w=...) {...}แก้ปัญหาได้ (และคุณจะได้รับคำเตือนเมื่อคุณลืม) ส่วนที่เหลือเป็นปัญหากับ RAII เช่นกัน การเรียกclose()"ตลอดเวลา" อาจจะหมายถึงหนึ่งครั้งต่อหมื่นสายดังนั้นมันจึงไม่เลวในขณะที่หน่วยความจำจะถูกจัดสรรเกือบทุกสาย Java
maaartinus

15

ถ้าคุณต้องการการรวบรวมขยะอัตโนมัติมีนักสะสมขยะและโดเมนสาธารณะที่ดีสำหรับ C ++ สำหรับแอปพลิเคชันที่เหมาะสมกับการรวบรวมขยะ C ++ เป็นภาษาที่รวบรวมขยะที่ยอดเยี่ยมด้วยประสิทธิภาพที่เปรียบเทียบได้ดีกับภาษาที่รวบรวมขยะอื่น ๆ ดูภาษาการเขียนโปรแกรม C ++ (รุ่นที่ 4)สำหรับการสนทนาของการรวบรวมขยะอัตโนมัติใน C ++ ดูเพิ่มเติม Hans-J ไซต์ของ Boehm สำหรับการรวบรวมขยะ C และ C ++ ( เก็บถาวร )

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

ที่มา: http://www.stroustrup.com/bs_faq.html#garbage-collection

สำหรับเหตุผลที่มันไม่ได้ติดตั้งไว้ภายในถ้าฉันจำได้อย่างถูกต้องมันถูกประดิษฐ์ขึ้นก่อนที่ GC จะเป็นในสิ่งนั้นและฉันไม่เชื่อว่าภาษานั้นอาจมี GC ได้หลายสาเหตุ

หวังว่านี่จะช่วยได้


"ด้วยประสิทธิภาพที่เปรียบเทียบได้ดีกับภาษาที่รวบรวมขยะอื่น ๆ " อ้างอิง?
Jon Harrop

1
ลิงก์ของฉันเสีย ฉันเขียนคำตอบนี้เมื่อ 5 ปีก่อน
Rayne

1
ตกลงฉันหวังว่าจะได้รับการตรวจสอบการอ้างสิทธิ์เหล่านี้อย่างอิสระเช่นไม่ใช่ Stroustrup หรือ Boehm :-)
Jon Harrop

12

Stroustrup ให้ความเห็นที่ดีเกี่ยวกับเรื่องนี้ในการประชุม Going Native 2013

เพียงข้ามไปประมาณ 25m50s ในวิดีโอนี้ (ฉันขอแนะนำให้ดูวิดีโอทั้งหมดจริง ๆ แต่สิ่งนี้จะข้ามไปที่เนื้อหาเกี่ยวกับการเก็บขยะ)

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

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

เขาแสดงตัวอย่างนี้:

void f(int n, int x) {
    Gadget *p = new Gadget{n};
    if(x<100) throw SomeException{};
    if(x<200) return;
    delete p;
}

สิ่งนี้ไม่ปลอดภัยใน C ++ แต่มันยังไม่ปลอดภัยใน Java! ใน C ++ หากฟังก์ชันส่งคืนก่อนกำหนดdeleteจะไม่ถูกเรียกใช้ แต่ถ้าคุณมีการรวบรวมขยะเต็มรูปแบบเช่นใน Java คุณจะได้รับคำแนะนำว่าวัตถุจะถูกทำลาย "ในอนาคต" ( อัปเดต:ยิ่งแย่ไปกว่านี้ Java ไม่สัญญาว่าจะโทรหาผู้เข้ารอบสุดท้าย - อาจจะไม่มีใครโทรมา) สิ่งนี้ไม่ดีพอหาก Gadget เก็บที่เปิดไฟล์ไว้หรือการเชื่อมต่อกับฐานข้อมูลหรือข้อมูลที่คุณบัฟเฟอร์สำหรับเขียนไปยังฐานข้อมูลในภายหลัง เราต้องการให้แกดเจ็ตถูกทำลายทันทีที่เสร็จสิ้นเพื่อให้ฟรีทรัพยากรเหล่านี้โดยเร็วที่สุด คุณไม่ต้องการให้เซิร์ฟเวอร์ฐานข้อมูลของคุณต้องดิ้นรนกับการเชื่อมต่อฐานข้อมูลนับพันที่ไม่ต้องการอีกต่อไป - ไม่ทราบว่าโปรแกรมของคุณทำงานเสร็จแล้ว

ดังนั้นทางออกคืออะไร? มีสองสามวิธี วิธีการที่ชัดเจนซึ่งคุณจะใช้สำหรับวัตถุส่วนใหญ่ของคุณคือ:

void f(int n, int x) {
    Gadget p = {n};  // Just leave it on the stack (where it belongs!)
    if(x<100) throw SomeException{};
    if(x<200) return;
}

การดำเนินการนี้ใช้อักขระน้อยลง มันไม่ได้newเข้ามาขวางทาง ไม่ต้องการให้คุณพิมพ์Gadgetสองครั้ง วัตถุถูกทำลายที่ส่วนท้ายของฟังก์ชัน หากนี่คือสิ่งที่คุณต้องการ Gadgets ประพฤติเช่นเดียวกับหรือint doubleคาดเดาได้ง่ายต่อการอ่านและง่ายต่อการสอน ทุกอย่างคือ 'คุณค่า' บางครั้งมีค่ามาก แต่ค่าจะง่ายต่อการสอนเพราะคุณไม่มี 'การกระทำในระยะไกล' ที่คุณได้รับจากพอยน์เตอร์ (หรือการอ้างอิง)

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

ขอบเขตและอายุการใช้งานมีความสำคัญ ส่วนใหญ่แล้วจะง่ายกว่าหากอายุการใช้งานเท่ากันกับขอบเขต ง่ายต่อการเข้าใจและสอนง่ายกว่า เมื่อคุณต้องการอายุการใช้งานที่แตกต่างกันควรอ่านรหัสที่คุณกำลังทำอย่างชัดเจนโดยใช้shared_ptrตัวอย่าง (หรือกลับ (ขนาดใหญ่) unique_ptrวัตถุโดยค่าใช้ประโยชน์จากการย้ายความหมายหรือ

นี่อาจดูเหมือนว่าเป็นปัญหาด้านประสิทธิภาพ เกิดอะไรขึ้นถ้าผมต้องการที่จะกลับมาเป็น Gadget จากfoo()? ความหมายของ C ++ 11 ทำให้ง่ายต่อการส่งคืนวัตถุขนาดใหญ่ เพิ่งเขียนGadget foo() { ... }และมันจะทำงานและทำงานได้อย่างรวดเร็ว คุณไม่จำเป็นต้องยุ่งกับ&&ตัวเองเพียงแค่คืนสิ่งต่าง ๆ ตามคุณค่าและภาษาก็มักจะสามารถทำการปรับให้เหมาะสมที่จำเป็น (แม้กระทั่งก่อน C ++ 03 คอมไพเลอร์ทำงานได้ดีอย่างน่าทึ่งที่หลีกเลี่ยงการทำสำเนาโดยไม่จำเป็น)

ดังที่ Stroustrup พูดที่อื่นในวิดีโอ (การถอดความ): "มีเพียงนักวิทยาศาสตร์คอมพิวเตอร์เท่านั้นที่จะยืนยันในการคัดลอกวัตถุแล้วทำลายต้นฉบับ (ผู้ชมหัวเราะ) ทำไมไม่เพียงแค่ย้ายวัตถุนั้นไปยังตำแหน่งใหม่โดยตรง? (ไม่ใช่นักวิทยาศาสตร์คอมพิวเตอร์) คาดหวัง "

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

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


1
ควรใช้ GC สำหรับวัตถุที่ไม่ได้รับทรัพยากร (เช่นขอให้หน่วยงานอื่นทำสิ่งต่าง ๆ แทน "จนกว่าจะมีประกาศ") หากGadgetไม่ได้ขอให้ผู้อื่นทำอะไรแทนรหัสต้นฉบับจะปลอดภัยอย่างสมบูรณ์ใน Java หากคำสั่งที่ไร้ความหมาย (กับ Java) deleteถูกลบออกไป
supercat

@supercat วัตถุที่มี destructors น่าเบื่อน่าสนใจ (ฉันไม่ได้นิยาม 'น่าเบื่อ' แต่โดยทั่วไปแล้วตัวทำลายที่ไม่จำเป็นต้องเรียกยกเว้นการปลดปล่อยหน่วยความจำ) อาจเป็นไปได้ที่คอมไพเลอร์แต่ละรายจะปฏิบัติshared_ptr<T>เป็นพิเศษเมื่อT'น่าเบื่อ' สามารถตัดสินใจที่จะไม่จัดการตัวนับการอ้างอิงสำหรับประเภทนั้นและใช้ GC แทน สิ่งนี้จะทำให้ GC สามารถใช้งานได้โดยไม่ต้องมีผู้พัฒนาแจ้งให้ทราบ shared_ptrก็สามารถถูกมองว่าเป็นตัวชี้ GC Tสำหรับที่เหมาะสม แต่มีข้อ จำกัด ในเรื่องนี้และมันจะทำให้หลาย ๆ โปรแกรมช้าลง
Aaron McDaid

ระบบชนิดที่ดีควรมีประเภทที่แตกต่างกันสำหรับวัตถุฮีปที่มีการจัดการ GC และ RAII เนื่องจากรูปแบบการใช้งานบางอย่างทำงานได้ดีกับระบบหนึ่งและไม่ดีมาก ใน .NET หรือ Java คำสั่งstring1=string2;จะดำเนินการได้อย่างรวดเร็วโดยไม่คำนึงถึงความยาวของสตริง (มันเป็นตัวอักษรอะไรมากไปกว่าการโหลดลงทะเบียนและลงทะเบียนร้านค้า) และไม่ต้องล็อคใด ๆ เพื่อให้มั่นใจว่าถ้ามีคำสั่งดังกล่าวข้างต้นจะถูกดำเนินการในขณะที่string2มี การเขียนstring1จะถือทั้งค่าเก่าหรือค่าใหม่โดยไม่มีพฤติกรรมที่ไม่ได้กำหนด)
supercat

ใน C ++ การมอบหมาย a shared_ptr<String>ต้องใช้การซิงโครไนซ์เบื้องหลังและการกำหนด a Stringอาจทำงานผิดปกติหากตัวแปรอ่านและเขียนพร้อมกัน กรณีที่ผู้ใช้ต้องการเขียนและอ่านStringพร้อมกันนั้นไม่ได้เป็นเรื่องธรรมดามากนัก แต่สามารถเกิดขึ้นได้เช่นหากมีรหัสบางอย่างที่ต้องการให้รายงานสถานะอย่างต่อเนื่องพร้อมใช้งานสำหรับเธรดอื่น ๆ ใน. NET และ Java สิ่งต่าง ๆ เพียงแค่ "ทำงาน"
supercat

1
@crossguy ไม่มีอะไรเปลี่ยนแปลงเว้นแต่ว่าคุณจะใช้มาตรการป้องกันที่ถูกต้อง Java ยังคงอนุญาตให้เรียกใช้ตัวเรียกรอบสุดท้ายได้ทันทีที่ตัวสร้างเสร็จสิ้น นี่คือตัวอย่างชีวิตจริง:“ finalize () เรียกใช้บนออบเจ็กต์ที่เข้าถึงได้อย่างมากใน Java 8 ” บทสรุปคือไม่เคยใช้คุณสมบัตินี้ซึ่งเกือบทุกคนยอมรับว่าเป็นความผิดพลาดในการออกแบบทางประวัติศาสตร์ของภาษา เมื่อเราทำตามคำแนะนำนั้นภาษาจะกำหนดระดับที่เรารัก
Holger

11

เพราะ C ++ ที่ทันสมัยไม่จำเป็นต้องมีการเก็บขยะ

คำตอบที่พบบ่อยของ Bjarne Stroustrup เกี่ยวกับเรื่องนี้กล่าวว่า :

ฉันไม่ชอบขยะ ฉันไม่ชอบที่ทิ้งขยะ อุดมคติของฉันคือกำจัดความต้องการเก็บขยะโดยไม่สร้างขยะ ตอนนี้เป็นไปได้


สถานการณ์สำหรับโค้ดที่เขียนวันนี้ (C ++ 17 และปฏิบัติตามแนวทางหลักอย่างเป็นทางการ ) มีดังนี้:

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

"ใช่แล้ว แต่สิ่งที่เกี่ยวกับ ...

... ถ้าฉันเพิ่งเขียนโค้ดตามที่เราเคยเขียน C ++ ในสมัยก่อน "

แน่นอนคุณสามารถเพิกเฉยต่อคำแนะนำทั้งหมดและเขียนรหัสแอปพลิเคชันที่รั่วไหล - และมันจะรวบรวมและเรียกใช้ (และรั่วไหล) เช่นเคย

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

... หากฉันreintrepret_cast? หรือการคำนวณทางคณิตศาสตร์ที่ซับซ้อน หรือแฮ็กอื่น ๆ ? "

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

  1. คุณจะทำเช่นนี้ไม่ค่อย (ในแง่ของสถานที่ในรหัสไม่จำเป็นต้องเป็นในส่วนของเวลาดำเนินการ)
  2. คุณจะทำสิ่งนี้โดยเจตนาไม่ใช่อย่างตั้งใจ
  3. การทำเช่นนั้นจะโดดเด่นใน codebase สอดคล้องกับแนวทาง
  4. มันเป็นรหัสประเภทที่คุณจะเลี่ยงผ่าน GC ในภาษาอื่นต่อไป

... การพัฒนาห้องสมุด? "

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


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

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


ลองคิดดูว่าคุณมีอาร์เรย์สตริงขนาดใหญ่ (คิดว่าหลายร้อยเมกะไบต์) ที่คุณกำลังสร้างทีละส่วนจากนั้นประมวลผลและสร้างใหม่ตามความยาวที่แตกต่างกัน รู้เพราะฉันต้องเปลี่ยนเป็นภาษาระดับสูงเพื่อรับมือ (แน่นอนคุณสามารถสร้าง GC ของคุณเองได้เช่นกัน)
www-0av-Com

2
@ user1863152: เป็นกรณีที่ตัวจัดสรรที่กำหนดเองจะมีประโยชน์ มันยังไม่จำเป็นต้องใช้ภาษาที่เป็นส่วนประกอบ GC ...
einpoklum

เพื่อ einpoklum: จริง มันเป็นแค่ม้าสำหรับหลักสูตร ความต้องการของฉันคือการประมวลผลแกลลอนข้อมูลการขนส่งผู้โดยสารที่เปลี่ยนแปลงแบบไดนามิก เรื่องที่น่าสนใจ .. เกิดขึ้นกับปรัชญาซอฟต์แวร์จริงๆ
www-0av-Com

GC ในขณะที่โลกของ Java และ. NET ได้ค้นพบว่ามีปัญหาใหญ่ - มันไม่ขยายขนาด เมื่อคุณมีวัตถุสดเป็นพันล้านในหน่วยความจำเมื่อเราทำวันนี้ด้วยซอฟต์แวร์ที่ไม่สำคัญคุณจะต้องเริ่มเขียนโค้ดเพื่อซ่อนสิ่งต่าง ๆ จาก GC เป็นภาระที่จะต้องมี GC ใน Java และ. NET
Zach Saw

10

แนวคิดเบื้องหลัง C ++ คือคุณจะไม่จ่ายผลกระทบต่อประสิทธิภาพการทำงานสำหรับคุณลักษณะที่คุณไม่ได้ใช้ ดังนั้นการเพิ่มการรวบรวมขยะอาจหมายถึงการให้บางโปรแกรมทำงานบนฮาร์ดแวร์อย่างที่ C ทำและบางอย่างอยู่ในประเภทของ virtual virtual machine

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


2
ฉันไม่คิดว่า GC ต้องการ VM คอมไพเลอร์สามารถเพิ่มรหัสไปยังการดำเนินการตัวชี้ทั้งหมดเพื่ออัปเดตสถานะโกลบอลในขณะที่เธรดแยกต่างหากจะรันในการลบวัตถุพื้นหลังตามต้องการ
user83255

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


4

หนึ่งในหลักการพื้นฐานที่อยู่เบื้องหลังภาษา C ดั้งเดิมคือหน่วยความจำประกอบด้วยลำดับของไบต์และรหัสต้องการเพียงการดูแลเกี่ยวกับความหมายของไบต์เหล่านั้นในเวลาที่แน่นอนที่พวกเขากำลังใช้ Modern C อนุญาตให้คอมไพเลอร์กำหนดข้อ จำกัด เพิ่มเติม แต่ C ประกอบด้วย - และ C ++ ยังคง - ความสามารถในการสลายตัวชี้ไปสู่ลำดับของไบต์ประกอบลำดับของไบต์ใด ๆ ที่มีค่าเดียวกันลงในตัวชี้แล้วใช้ตัวชี้นั้นเพื่อ เข้าถึงวัตถุก่อนหน้า

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

สิ่งแปลกประหลาดที่น่าสนใจของเฟรมเวิร์กที่รวบรวมขยะจำนวนมากคือการอ้างอิงวัตถุที่ไม่ได้กำหนดโดยรูปแบบบิตที่อยู่ในนั้น แต่จากความสัมพันธ์ระหว่างบิตที่มีในการอ้างอิงวัตถุและข้อมูลอื่น ๆ ที่จัดขึ้นที่อื่น ใน C และ C ++ หากรูปแบบบิตที่เก็บไว้ในตัวชี้ระบุวัตถุรูปแบบบิตนั้นจะระบุวัตถุนั้นจนกว่าวัตถุนั้นจะถูกทำลายอย่างชัดเจน ในระบบ GC ทั่วไปวัตถุอาจถูกแทนด้วยรูปแบบบิต 0x1234ABCD ในช่วงเวลาหนึ่ง แต่วัฏจักร GC ถัดไปอาจแทนที่การอ้างอิงทั้งหมดไปยัง 0x1234ABCD ด้วยการอ้างอิงถึง 0x4321BABE โดยที่วัตถุนั้นจะถูกแทนด้วยรูปแบบหลัง แม้ว่าจะมีการแสดงรูปแบบบิตที่เกี่ยวข้องกับการอ้างอิงวัตถุและจากนั้นอ่านกลับจากคีย์บอร์ด


นั่นเป็นจุดที่ดีจริงๆฉันเพิ่งขโมยบางส่วนจากพอยน์เตอร์ของฉันเพราะไม่เช่นนั้นจะมีแคชที่โง่จำนวนมาก
สัญจรภายใน

@PasserBy: ฉันสงสัยว่าแอปพลิเคชั่นจำนวนมากที่ใช้พอยน์เตอร์แบบ 64- บิตจะได้รับประโยชน์มากขึ้นจากการใช้พอยน์เตอร์แบบ 32 บิตที่ปรับขนาดเป็นการอ้างอิงวัตถุ - ความเร็วที่เก็บเกิน? เครื่องมี RAM เพียงพอที่การใช้ RAM ของตัวชี้ 64- บิตอาจไม่สำคัญยกเว้นว่าพวกเขาจะกลืนสองเท่าของแคชเท่ากับตัวชี้ 32- บิต
supercat

3

การพูดคุยทางเทคนิคทั้งหมดเป็นการสรุปแนวคิด

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

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

ดังนั้นทางออกที่ถูกต้องคือการแบ่งแอปพลิเคชันออกเป็นส่วนที่ต้องการ GC และชิ้นส่วนที่ไม่ต้องการ ในกรณีของตัวอย่างเว็บเบราว์เซอร์ด้านบนหากทรีเอกสารถูกจัดสรรด้วย malloc แต่จาวาสคริปต์รันด้วย GC ดังนั้นทุกครั้งที่ GC kicks ในสแกนเฉพาะหน่วยความจำส่วนเล็ก ๆ และองค์ประกอบ PAGED OUT ทั้งหมดของหน่วยความจำสำหรับ แผนผังเอกสารไม่จำเป็นต้องทำการเพจอีก

เพื่อทำความเข้าใจปัญหานี้เพิ่มเติมค้นหาหน่วยความจำเสมือนและวิธีการใช้งานในคอมพิวเตอร์ มันเป็นเรื่องของความจริงที่ว่า 2GB มีให้กับโปรแกรมเมื่อไม่มี RAM ขนาดนั้นจริงๆ ในคอมพิวเตอร์สมัยใหม่ที่มี 2GB RAM สำหรับระบบ 32BIt ไม่ใช่ปัญหาดังกล่าวหากมีเพียงโปรแกรมเดียวที่กำลังทำงาน

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

ดังนั้นคำตอบของฉันที่จะทำให้สั้นลงคือจำนวนของ PAGE FAULTS ที่เกิดขึ้นจากการสัมผัสหน่วยความจำทั้งหมดทำให้เกิด GC แบบเต็มสำหรับวัตถุทั้งหมดในโปรแกรมที่ไม่สามารถทำได้และโปรแกรมเมอร์จึงต้องดู GC เป็นตัวช่วยสำหรับสิ่งต่าง ๆ เช่นสคริปต์ และฐานข้อมูลทำงานได้ แต่ทำสิ่งปกติด้วยการจัดการหน่วยความจำด้วยตนเอง

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


3

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

คำตอบยาว: เช่นเดียวกับ C, C ++ เป็นภาษาระบบ นี่หมายความว่ามันถูกใช้เมื่อคุณกำลังเขียนรหัสระบบเช่นระบบปฏิบัติการ กล่าวอีกนัยหนึ่ง C ++ ได้รับการออกแบบเช่นเดียวกับ C ที่มีประสิทธิภาพดีที่สุดเป็นเป้าหมายหลัก มาตรฐานของภาษาจะไม่เพิ่มคุณสมบัติใด ๆ ที่อาจขัดขวางวัตถุประสงค์ด้านประสิทธิภาพ

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

สุดท้ายถ้าการควบคุม (ฮาร์ดแวร์รายละเอียด ฯลฯ ) และประสิทธิภาพ (เวลาพื้นที่พลังงาน ฯลฯ ) ไม่ใช่ข้อ จำกัด หลักดังนั้น C ++ ไม่ใช่เครื่องมือเขียน ภาษาอื่นอาจให้บริการที่ดีขึ้นและให้การจัดการรันไทม์ [ซ่อน] มากขึ้นพร้อมค่าใช้จ่ายที่จำเป็น


3

เมื่อเราเปรียบเทียบ C ++ กับ Java เราจะเห็นว่า C ++ ไม่ได้รับการออกแบบโดยคำนึงถึง Garbage Collection ในใจขณะที่ Java เป็น

การมีสิ่งต่าง ๆ เช่นพอยน์เตอร์พ้อยท์ใน C-Style ไม่เพียง แต่จะไม่ดีสำหรับการใช้งานแบบ GC เท่านั้น แต่มันยังทำลายความเข้ากันได้แบบย้อนหลังสำหรับ C ++ จำนวนมากซึ่งเป็นรหัสดั้งเดิม

นอกเหนือจากนั้น C ++ เป็นภาษาที่มีวัตถุประสงค์เพื่อให้ใช้งานได้แบบสแตนด์อโลนแทนการใช้สภาพแวดล้อมแบบรันไทม์ที่ซับซ้อน

ทั้งหมดในทั้งหมด: ใช่อาจเป็นไปได้ที่จะเพิ่ม Garbage Collection ลงใน C ++ แต่เพื่อความต่อเนื่องมันจะดีกว่าถ้าไม่ทำเช่นนั้น


1
การเพิ่มหน่วยความจำและ destructors ที่ทำงานอยู่เป็นปัญหาที่แยกจากกันโดยสิ้นเชิง (Java ไม่มี destructors ซึ่งเป็น PITA) GC เพิ่มหน่วยความจำจะไม่เรียกใช้ dtors
curiousguy

0

ส่วนใหญ่ด้วยเหตุผลสองประการ:

  1. เพราะมันไม่ต้องการ (IMHO)
  2. เพราะมันเข้ากันไม่ได้กับ RAII ซึ่งเป็นรากฐานที่สำคัญของ C ++

C ++ มีการจัดการหน่วยความจำด้วยตนเองแล้ว, การจัดสรรสแต็ค, RAII, คอนเทนเนอร์, พอยน์เตอร์อัตโนมัติ, สมาร์ทพอยน์เตอร์ ... นั่นควรจะเพียงพอแล้ว นักสะสมขยะเหมาะสำหรับโปรแกรมเมอร์ที่ขี้เกียจที่ไม่ต้องการใช้เวลา 5 นาทีคิดว่าใครควรเป็นเจ้าของวัตถุใดหรือเมื่อไรที่ควรปล่อยทรัพยากร นั่นไม่ใช่วิธีที่เราทำใน C ++


มีอัลกอริทึม (ใหม่กว่า) จำนวนมากซึ่งยากที่จะนำไปใช้โดยไม่ต้องมีการรวบรวมขยะ เวลาย้ายไป นวัตกรรมยังมาจากข้อมูลเชิงลึกใหม่ที่เข้ากันได้ดีกับ (การเก็บขยะ) ภาษาระดับสูง ลองนำกลับไปใช้ใหม่กับ GC ฟรี C ++ คุณจะสังเกตเห็นการกระแทกบนท้องถนน (ฉันรู้ว่าฉันควรยกตัวอย่าง แต่ตอนนี้ฉันรีบร้อนขอโทษหนึ่งที่ฉันนึกถึงตอนนี้หมุนรอบโครงสร้างข้อมูลถาวรซึ่งการนับการอ้างอิงจะไม่ทำงาน)
BitTickler

0

การรวบรวมขยะเป็นระดับต่ำไปสู่กระบวนทัศน์ระดับสูง

หากคุณดูวิธีจัดการสตริงในภาษาที่มีการรวบรวมขยะคุณจะพบว่าอนุญาตให้ใช้ฟังก์ชันการจัดการสตริงระดับสูงเท่านั้นและไม่อนุญาตให้เข้าถึงไบนารีกับสตริง เพียงแค่ใส่ฟังก์ชั่นสตริงทั้งหมดก่อนตรวจสอบพอยน์เตอร์เพื่อดูว่าสตริงอยู่ที่ไหนแม้ว่าคุณจะวาดเพียงไบต์ ดังนั้นถ้าคุณทำลูปที่ประมวลผลแต่ละไบต์ในสตริงในภาษาที่มีการรวบรวมขยะมันจะต้องคำนวณตำแหน่งฐานบวกชดเชยสำหรับการทำซ้ำแต่ละครั้งเพราะมันไม่สามารถรู้ได้เมื่อสตริงได้ย้าย ถ้าอย่างนั้นคุณต้องคิดถึง heaps, stack, threads และอื่น ๆ

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