ทำไมต้องมีการรวบรวมขยะหากตัวชี้สมาร์ทอยู่ที่นั่น


67

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

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


1
สิ่งหนึ่งที่ผมเข้าใจหลังจากที่ถามคำถามนี้ชี้สมาร์ทต้องการ RAII การจัดการ deallocation
Gulshan

8
ตัวชี้อัจฉริยะหมายถึงการใช้ RAII สำหรับ GC;)
Dario

Heh, c # ควรมีตัวเลือกสำหรับการจัดการ "การรวบรวมขยะ" ทั้งหมดด้วย RAII การอ้างอิงแบบวนรอบสามารถตรวจพบได้ในการปิดแอปพลิเคชันสิ่งที่เราต้องการคือการดูว่าการจัดสรรใดยังคงอยู่ในหน่วยความจำหลังจาก Program.cs-class ถูกจัดสรรคืน จากนั้นการอ้างอิงแบบวงกลมสามารถถูกแทนที่ด้วยการอ้างอิงบางสัปดาห์
AareP

4
คำตอบ
Gulshan

คำตอบ:


67

ดังนั้นจุดประสงค์ในการใช้การรวบรวมขยะคืออะไร

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

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

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

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


23
ไม่อยากเชื่อเลยว่าคำตอบนี้จบลงด้วยคำตอบที่ดีที่สุดแล้ว มันแสดงให้เห็นถึงการขาดความเข้าใจโดยรวมของตัวชี้สมาร์ท C ++ และทำให้การเรียกร้องที่ไม่ตรงกับความเป็นจริงที่มันไร้สาระอย่างมาก อันดับแรกตัวชี้อัจฉริยะที่ในรหัส C ++ ที่ออกแบบมาอย่างดีจะเด่นที่สุดคือตัวชี้ที่ไม่ซ้ำกันไม่ใช่ตัวชี้การแชร์ en.cppreference.com/w/cpp/memory/unique_ptr และประการที่สองฉันไม่อยากจะเชื่อเลยว่าคุณอ้างถึงข้อดีของ 'ประสิทธิภาพ' และข้อดีของการเก็บขยะที่ไม่ได้กำหนดเวลาจริงผ่านตัวชี้สมาร์ท
user1703394

4
@ user1703394 ดูเหมือนว่าผู้ตอบได้แบ่งปันพอยน์เตอร์ในใจ (ถูกหรือผิดฉันไม่แน่ใจว่า OPs แนะนำอะไร) ซึ่งมีประสิทธิภาพน้อยกว่าการรวบรวมขยะที่ไม่ได้กำหนดไว้
Nathan Cooper

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

4
"ตัวชี้สมาร์ทไม่ใช่แนวคิดที่กว้างกว่า" อย่างจริงจังหรือ คุณไม่ทราบว่าคำสั่งนั้นจะทำลายอาร์กิวเมนต์ที่ถูกต้องทั้งหมดที่คุณทำจนถึงตอนนี้ อาจมีลักษณะที่เป็นเจ้าของ Rust และย้ายความหมาย: koerbitz.me/posts/ ...... มันง่ายสำหรับผู้ที่มีประสบการณ์ในอดีตกับ C ++ เพื่อพลาดข้อเท็จจริงที่ C ++ 11 / C ++ 14 พร้อมโมเดลหน่วยความจำ พอยน์เตอร์และซีแมนทิกส์เคลื่อนที่เป็นสัตว์ที่ต่างไปจากเดิมอย่างสิ้นเชิง มาดูกันว่า Rust ทำอย่างไรมันสะอาดกว่า C ++ และให้มุมมองใหม่ ๆ
user1703394

6
@ user1703394: "การหยุดชั่วคราวไม่ จำกัด เนื่องจาก destructors เป็นคุณสมบัติที่โชคร้ายของ RAII ที่ใช้สำหรับทรัพยากรที่ไม่ใช่หน่วยความจำ" ไม่ไม่มีสิ่งใดที่เกี่ยวข้องกับทรัพยากรที่ไม่ใช่หน่วยความจำ
Jon Harrop

63

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

มีสองคำตอบสำหรับคำถามนั้น สำคัญที่สุดก่อน:

  1. คุณมั่นใจได้ว่ารหัสทั้งหมดสามารถใช้เพื่อทำงานร่วมกันได้ นี่คือผมคิดว่าเหตุผลใหญ่ว่าทำไมนำมาใช้รหัสและการแบ่งปันรหัสไม่ได้จริงๆจะปิดจนกว่า Java / C # / หลาม / ทับทิม ห้องสมุดจำเป็นต้องสื่อสารและภาษาที่ใช้ร่วมกันที่เชื่อถือได้เพียงอย่างเดียวคือสิ่งที่อยู่ในข้อมูลจำเพาะภาษา (และในระดับมาตรฐานของห้องสมุด) หากคุณเคยพยายามนำไลบรารี่กลับมาใช้ใหม่ใน C ++ คุณอาจประสบกับความเจ็บปวดอันน่าสยดสยองที่ไม่มีความหมายแบบมาตรฐานของหน่วยความจำเกิดขึ้น ฉันต้องการส่งผ่านโครงสร้างไปยัง lib บางส่วน ฉันจะผ่านการอ้างอิงได้หรือไม่ ชี้? ?scoped_ptrsmart_ptr? ฉันกำลังผ่านการเป็นเจ้าของหรือไม่? มีวิธีที่จะระบุว่า? เกิดอะไรขึ้นถ้า lib ต้องการจัดสรร? ฉันต้องจัดสรรให้หรือไม่ การไม่ทำให้ส่วนของการจัดการหน่วยความจำของภาษา C ++ บังคับให้แต่ละคู่ไลบรารีต้องเจรจากลยุทธ์เฉพาะของตนเองที่นี่และเป็นการยากที่จะให้ทุกคนเห็นด้วย GC ทำให้ไม่ใช่ประเด็นที่สมบูรณ์

  2. คุณสามารถออกแบบไวยากรณ์ที่อยู่รอบ ๆ เนื่องจาก C ++ ไม่ได้ห่อหุ้มการจัดการหน่วยความจำของตัวเองจึงต้องมีช่วงของฮุก syntactic เพื่อให้รหัสระดับผู้ใช้แสดงรายละเอียดทั้งหมด คุณมีพอยน์เตอร์, การอ้างอิง, constโอเปอเรเตอร์ dereferencing, โอเปอเรเตอร์ทางอ้อม, ที่อยู่ของ ฯลฯ หากคุณม้วนการจัดการหน่วยความจำเป็นภาษาของตัวเองไวยากรณ์สามารถออกแบบได้ ตัวดำเนินการทั้งหมดนั้นหายไปและภาษาก็ดูสะอาดและเรียบง่ายขึ้น

  3. คุณได้รับผลตอบแทนสูงจากการลงทุน ค่าใด ๆ ของรหัสที่สร้างจะถูกคูณด้วยจำนวนผู้ใช้ ซึ่งหมายความว่ายิ่งมีผู้ใช้มากเท่าไหร่คุณก็จะสามารถใช้จ่ายกับซอฟต์แวร์ได้มากขึ้นเท่านั้น เมื่อคุณย้ายคุณลักษณะที่เป็นภาษาที่ทุกผู้ใช้ภาษาที่จะใช้มัน ซึ่งหมายความว่าคุณสามารถจัดสรรความพยายามได้มากกว่าที่จะทำได้กับไลบรารีที่ใช้โดยชุดย่อยของผู้ใช้เหล่านั้นเท่านั้น นี่คือเหตุผลที่ภาษาอย่าง Java และ C # มี VM อันดับหนึ่งอย่างแน่นอนและนักสะสมขยะคุณภาพสูงอย่างน่าอัศจรรย์ค่าใช้จ่ายในการพัฒนาจะถูกตัดจำหน่ายไปยังผู้ใช้หลายล้านคน


คำตอบที่ยอดเยี่ยม! ถ้าฉันสามารถโหวตได้มากกว่าหนึ่งครั้ง ...
Dean Harding

10
เป็นที่น่าสังเกตว่าการรวบรวมขยะไม่ได้นำไปใช้จริงในภาษา C # แต่ใน. NET Frameworkโดยเฉพาะ Common Language Runtime (CLR)
Robert Harvey

6
@RobertHarvey: มันไม่ได้ใช้งานโดยภาษา แต่มันจะไม่ทำงานหากไม่มีความร่วมมือของภาษา ตัวอย่างเช่นคอมไพเลอร์จะต้องมีข้อมูลที่ระบุในทุกจุดในรหัสที่ตั้งของทุก register หรือ stack-frame offset ที่เก็บการอ้างอิงไปยังวัตถุ unpinned นั่นคือข้อยกเว้นที่ไม่เปลี่ยนแปลงแน่นอนซึ่งไม่สามารถยึดถือได้หากไม่มีการสนับสนุนทางภาษา
supercat

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

34

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

ถูกต้องมากขึ้นพวกเขาจะถูกปล่อยออกมาเมื่อพวกเขาไม่สามารถเข้าถึงโปรแกรมได้เนื่องจากวัตถุที่อ้างอิงเป็นวงกลมจะไม่ถูกปล่อยออกมาอย่างอื่น

พอยน์เตอร์สมาร์ทเพียงอ้างถึงโครงสร้างใด ๆ ที่ทำงานเหมือนตัวชี้ธรรมดา แต่มีฟังก์ชั่นพิเศษบางอย่างแนบมา สิ่งเหล่านี้รวมถึงแต่ไม่ จำกัด เพียงการจัดสรรคืน แต่ยังรวมถึงการคัดลอกเมื่อเขียนเช็คที่ถูกผูกไว้ ...

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

แต่ขบวนความคิดดำเนินไปในทางต่อไปนี้:

  1. การเก็บขยะเป็นสิ่งที่ยอดเยี่ยมเพราะสะดวกและฉันต้องดูแลสิ่งต่าง ๆ ให้น้อยลง
  2. ดังนั้น: ฉันต้องการเก็บขยะในภาษาของฉัน
  3. ตอนนี้จะนำ GC มาเป็นภาษาของฉันได้อย่างไร

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

แต่ใน C ++ ไม่มีการรวบรวมขยะ หากเราจัดสรรตัวชี้บางส่วนint* p = new int;และอยู่นอกขอบเขตpตัวเองจะถูกลบออกจากสแต็ก แต่ไม่มีใครดูแลหน่วยความจำที่จัดสรร

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

นี่คือเฉพาะ C ++ สูงทั้งหมด: การบรรทุกเกินพิกัด, เทมเพลต, destructors, ... ในสถานการณ์เฉพาะภาษานี้คุณได้พัฒนาพอยน์เตอร์อัจฉริยะเพื่อให้ GC ที่คุณต้องการ

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

พอยน์เตอร์สมาร์ทเช่นใน C ++ อาจจะไม่สามารถทำได้ในภาษาอย่าง C # ซึ่งไม่มีการทำลายที่กำหนดเลย (C # ทำงานได้โดยการให้น้ำตาล syntactic สำหรับการเรียก.Dispose()วัตถุบางอย่าง) ในที่สุดทรัพยากรที่ไม่มีการอ้างอิงจะถูกเรียกคืนโดย GC แต่จะไม่ได้กำหนดเมื่อจะเกิดขึ้นอย่างแน่นอน

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


C # จะมีรูปแบบของการทำลายกำหนดผ่านและIDisposable usingแต่ต้องใช้ความพยายามของโปรแกรมเมอร์เล็กน้อยซึ่งเป็นสาเหตุที่มักใช้กับทรัพยากรที่หายากมากเช่นการจัดการการเชื่อมต่อฐานข้อมูล
JSB ձոգչ

7
@JSBangs: แน่นอน เช่นเดียวกับ C ++ สร้างพอยน์เตอร์อัจฉริยะรอบ ๆ RAII เพื่อรับ GC, C # ไปทางอื่นและสร้าง "smart disposers" รอบ ๆ GC เพื่อให้ได้ RAII;) อันที่จริงมันเป็นความอัปยศที่ RAII ยากมากใน C # เพราะยอดเยี่ยม - การจัดการทรัพยากรที่ปลอดภัย ยกตัวอย่างเช่น F # พยายามใช้IDisposableไวยากรณ์ที่ง่ายขึ้นโดยเพียงแค่แทนที่การชุมนุมlet ident = valueด้วยuse ident = value...
Dario

@Dario: "C # ไปทางอื่นและสร้าง 'ตัวคัดสรรอัจฉริยะ' รอบ GC เพื่อรับ RAII" RAII ใน C # with usingไม่มีส่วนเกี่ยวข้องกับการรวบรวมขยะเลยเพียงแค่เรียกใช้ฟังก์ชั่นเมื่อตัวแปรอยู่นอกขอบเขตเช่นเดียวกับ destructors ใน C ++
Jon Harrop

1
@ จอน Harrop: โปรดอะไรนะ ข้อความที่คุณอ้างถึงเป็นเรื่องเกี่ยวกับ Destructor C ++ แบบธรรมดาโดยไม่มีการอ้างอิง / ตัวชี้สมาร์ท / การรวบรวมขยะที่เกี่ยวข้อง
Dario

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

4

ในใจของฉันมีความแตกต่างใหญ่สองอย่างระหว่างการรวบรวมขยะและตัวชี้อัจฉริยะที่ใช้สำหรับการจัดการหน่วยความจำ:

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

อดีตหมายถึงว่า GC จะรวบรวมขยะที่ตัวชี้สมาร์ทจะไม่; หากคุณใช้พอยน์เตอร์อัจฉริยะคุณต้องหลีกเลี่ยงการสร้างขยะประเภทนี้หรือเตรียมพร้อมที่จะจัดการกับมันด้วยตนเอง

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

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

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


6
@Tom: ดูคำตอบของ Dario สำหรับรายละเอียดเกี่ยวกับพอยน์เตอร์พอยน์เตอร์ สำหรับข้อดีของสมาร์ทพอยน์เตอร์ - การจัดสรรคืนที่ จำกัด สามารถเป็นประโยชน์อย่างมากเมื่อใช้เพื่อควบคุมทรัพยากร (ไม่เพียง แต่หน่วยความจำเท่านั้น) ในความเป็นจริงนี้ได้รับการพิสูจน์แล้วดังนั้นสิ่งสำคัญที่ไมโครซอฟท์ได้แนะนำusingบล็อกในรุ่นต่อมาของ C # นอกจากนี้พฤติกรรมแบบ nondeterministic ของ GCs สามารถถูกห้ามในระบบเรียลไทม์ (ซึ่งเป็นเหตุผลที่ GCs ไม่ได้ใช้งานที่นั่น) นอกจากนี้ยังให้ไม่ลืมว่า GCs มีเพื่อที่ซับซ้อนในการได้รับสิทธิว่าส่วนใหญ่จริงรั่วหน่วยความจำและจะไม่มีประสิทธิภาพค่อนข้าง (เช่น Boehm ... )
Konrad Rudolph

6
ฉันคิดว่า nondeterminism ของ GCs เป็นบิตของปลาเฮอริ่งแดง - มีระบบ GC ที่เหมาะสำหรับการใช้งานแบบเรียลไทม์ (เช่น Recycler ของ IBM) แม้ว่าเครื่องที่คุณเห็นในเดสก์ท็อปและเซิร์ฟเวอร์ VM จะไม่ใช่ก็ตาม นอกจากนี้การใช้สมาร์ทพอยน์เตอร์หมายถึงการใช้ malloc / free และการใช้งานทั่วไปของ malloc นั้นเป็นแบบไม่ จำกัด เนื่องจากจำเป็นต้องค้นหารายการฟรี การย้ายระบบ GC มีมากขึ้นครั้งจัดสรรกำหนดกว่า malloc / ระบบฟรี แต่ของหลักสูตรที่กำหนดขึ้นน้อยครั้ง deallocation
Tom Anderson

3
สำหรับความซับซ้อน: ใช่ GCs มีความซับซ้อน แต่ฉันไม่ทราบว่า "หน่วยความจำรั่วจริงและไม่มีประสิทธิภาพ" และจะสนใจดูหลักฐานบางอย่าง Boehm ไม่ได้เป็นหลักฐานเพราะเป็นการใช้งานแบบดั้งเดิมและสร้างขึ้นเพื่อรับใช้ภาษา C ซึ่ง GC ที่ถูกต้องนั้นเป็นไปไม่ได้เนื่องจากไม่มีความปลอดภัยในการพิมพ์ มันเป็นความพยายามที่กล้าหาญและการทำงานนั้นน่าประทับใจมาก แต่คุณไม่สามารถถือเป็นแบบอย่างของ GC ได้
Tom Anderson

8
@ จอน: ไม่ต้องพล่าม bugzilla.novell.com/show_bug.cgi?id=621899หรือโดยทั่วไปแล้ว: flyingfrogblog.blogspot.com/2009/01/…นี่เป็นที่รู้จักกันดีและเป็นทรัพย์สินของ GCs ที่อนุรักษ์นิยมทั้งหมด
Konrad Rudolph

3
"ต้นทุนรันไทม์ของ GC สมัยใหม่น้อยกว่าระบบ malloc / free ปกติ" ปลาเฮอริ่งแดงที่นี่ นี่เป็นเพียงเพราะ malloc ดั้งเดิมเป็นอัลกอริทึมที่ไม่มีประสิทธิภาพอย่างน่ากลัว ผู้จัดสรรสมัยใหม่ที่ใช้ถังหลายถังสำหรับขนาดบล็อกที่แตกต่างกันจะเร็วกว่าในการจัดสรรและมีแนวโน้มน้อยกว่าในการแยกส่วนของฮีปและยังให้การจัดสรรคืนที่รวดเร็ว
Mason Wheeler

3

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

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

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

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


1
หมายความว่าRustไม่ต้องการเก็บขยะหรือไม่
Gulshan

1
@Gulshan Rust เป็นหนึ่งในไม่กี่ภาษาที่รองรับพอยน์เตอร์ที่ปลอดภัย
CodesInChaos

2

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

ปัญหาคือถ้าคุณมีการอ้างอิงแบบวงกลม นั่นคือ A มีการอ้างอิงถึง B, B มีการอ้างอิงถึง C และ C มีการอ้างอิงถึง A หากคุณใช้ตัวชี้สมาร์ทดังนั้นเพื่อที่จะเพิ่มหน่วยความจำที่เกี่ยวข้องกับ A, B & C คุณต้องด้วยตนเอง เข้าไปที่นั่น "ทำลาย" การอ้างอิงแบบวงกลม (เช่นใช้weak_ptrใน C ++)

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

ด้วยวิธีนี้การอ้างอิงแบบวนรอบไม่สำคัญอีกต่อไป - ตราบใดที่ไม่สามารถเข้าถึง A, B และ C ได้หน่วยความจำสามารถเรียกคืนได้

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

แน่นอนว่าใน C ++ จำนวนหน่วยความจำที่จัดสรรฮีปมักจะน้อยกว่าภาษาอ้างอิงหนักเช่น C # /. NET แต่นั่นไม่ใช่ปัญหาการรวบรวมขยะกับตัวชี้สมาร์ท

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


2

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

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

นอกจากนี้ GNU libc มีเครื่องมือที่มีประสิทธิภาพมากขึ้นสำหรับหน่วยความจำ unallocating ดูobstacks ต้องสังเกตุว่าฉันไม่มีประสบการณ์กับสิ่งกีดขวางฉันไม่เคยใช้มัน


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

ใช่แน่นอน GC นั้นสะดวกสบายกว่ามาก (โดยเฉพาะอย่างยิ่งสำหรับผู้เริ่มต้น: ไม่มีปัญหาเรื่องการเป็นเจ้าของไม่มีแม้กระทั่งตัวดำเนินการลบ)
ern0

3
@ ern0: ไม่ จุดรวมของตัวชี้สมาร์ท (นับการอ้างอิง) คือไม่มีปัญหาการเป็นเจ้าของและไม่มีตัวดำเนินการลบ
Konrad Rudolph

3
@ จอน: ซึ่งโดยสุจริตเป็นส่วนใหญ่ หากคุณจำสถานะวัตถุร่วมกันระหว่างเธรดที่แตกต่างกันคุณจะมีปัญหาที่แตกต่างกันโดยสิ้นเชิง ฉันจะยอมรับว่าโปรแกรมหลาย ๆ คนทำเช่นนั้น แต่นี่เป็นผลสืบเนื่องมาจากทฤษฏีการทำเกลียวที่ไม่ดีซึ่งมีอยู่จนกระทั่งเมื่อไม่นานมานี้และมันไม่ใช่วิธีที่ดีในการทำมัลติเธรด
Konrad Rudolph

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

2

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

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

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

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

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


1
"คุณจะมีกิจกรรมการจัดสรรจำนวนมากเกิดขึ้น" ลู่วิ่งของเบเกอร์เป็นตัวอย่างของตัวเก็บขยะที่เพิ่มขึ้นอย่างสวยงาม memorymanagement.org/glossary/t.html#troller
Jon Harrop

1

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

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


1

มันเป็นคลื่นความถี่

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

"ฉันจะบอกคุณว่าต้องทำอย่างไรคุณทำได้เชื่อฉัน"

การรวบรวมขยะคือส่วนอื่น ๆ ของสเปกตรัม คุณมีการควบคุมน้อยมาก แต่ก็มีการดูแลสำหรับคุณ:

"ฉันจะบอกคุณว่าฉันต้องการคุณทำให้มันเกิดขึ้น"

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

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


0

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

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

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