ตัวรวบรวมข้อมูลขยะป้องกันไม่ให้หน่วยความจำทั้งหมดถูกสแกนในทุกการรวบรวมอย่างไร


16

ตัวรวบรวมขยะ (อย่างน้อย Mono's และ. NET) บางตัวมีพื้นที่หน่วยความจำระยะสั้นซึ่งสแกนบ่อยและพื้นที่หน่วยความจำรองที่สแกนน้อยกว่า โมโนเรียกสถานเลี้ยงเด็กแห่งนี้

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

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

ฉันทำบางสิ่งบางอย่างหายไปหรือว่าตัวรวบรวมขยะกำลังสแกนวัตถุทั้งหมดและทุกการอ้างอิงทุกครั้งที่มีการรวบรวมหรือไม่


1
ภาพรวมที่ดีอยู่ในบทความThe Art of Garbage Collection Tuningเขียนโดย Angelika Langer อย่างเป็นทางการมันเกี่ยวกับวิธีการที่จะทำใน Java แต่แนวคิดที่นำเสนอเป็นผู้ไม่เชื่อเรื่องภาษามากสวย
ริ้น

คำตอบ:


14

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

  1. หลังจากการรวบรวมวัตถุทั้งหมดที่ยังคงมีอยู่จะเป็นรุ่นขั้นต่ำ (เช่นใน. net หลังจากคอลเลกชัน Gen0 วัตถุทั้งหมดคือ Gen1 หรือ Gen2; หลังจากการรวบรวม Gen1 หรือ Gen2 วัตถุทั้งหมดเป็น Gen2)
  2. วัตถุหรือส่วนของมันซึ่งไม่ได้ถูกเขียนขึ้นตั้งแต่การสะสมที่ส่งเสริมทุกอย่างสู่รุ่น N หรือสูงกว่าไม่สามารถมีการอ้างอิงใด ๆ กับวัตถุของคนรุ่นต่ำ
  3. หากวัตถุมาถึงรุ่นหนึ่งก็ไม่จำเป็นต้องระบุว่าสามารถเข้าถึงได้เพื่อให้แน่ใจว่ามีการเก็บรักษาเมื่อรวบรวมรุ่นที่ต่ำกว่า

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

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


การเคลื่อนย้ายบล็อกหน่วยความจำรอบ ๆ นั้นมีราคาแพงในระบบใด ๆ ดังนั้นการปรับปรุงการกวาดจึงเป็นประโยชน์แม้กับระบบ Quad Ghz CPU ของคุณ
gbjbaanb

@gbjbaanb: ในหลาย ๆ กรณีค่าใช้จ่ายในการสแกนทุกอย่างเพื่อค้นหาวัตถุที่มีชีวิตจะมีความสำคัญและน่ารังเกียจแม้ว่าการเคลื่อนย้ายวัตถุนั้นฟรีทั้งหมด ดังนั้นควรปฏิบัติเมื่อหลีกเลี่ยงการสแกนวัตถุเก่า ในทางตรงกันข้ามการละเว้นจากการบีบอัดวัตถุที่เก่ากว่าเป็นการเพิ่มประสิทธิภาพอย่างง่ายซึ่งสามารถทำได้แม้ในกรอบง่ายๆ BTW หากมีการออกแบบกรอบ GC สำหรับระบบฝังตัวเล็ก ๆ การสนับสนุนการประกาศสำหรับวัตถุที่ไม่เปลี่ยนรูปแบบอาจเป็นประโยชน์ การติดตามว่าวัตถุที่เปลี่ยนแปลงไม่ได้มีการเปลี่ยนแปลงหรือไม่ แต่อาจทำได้ดีในการ ...
supercat

... เพียงสมมติว่าวัตถุที่ไม่แน่นอนต้องสแกนทุกครั้งที่ผ่าน GC แต่วัตถุที่เปลี่ยนแปลงไม่ได้นั้นไม่ต้องทำ แม้ว่าวิธีเดียวที่จะสร้างวัตถุที่ไม่เปลี่ยนรูปคือการสร้าง "ต้นแบบ" ในพื้นที่ที่ไม่แน่นอนและคัดลอกแล้วการดำเนินการคัดลอกพิเศษครั้งเดียวสามารถหลีกเลี่ยงความต้องการสแกนวัตถุในการดำเนินงาน GC ในอนาคต
supercat

อนึ่งประสิทธิภาพการเก็บขยะในการนำไปใช้งานพื้นฐานของ Microsoft จาก BASIC สำหรับไมโครโพรเซสเซอร์ 6502 (และบางทีอาจเป็นอย่างอื่น) ได้เพิ่มขึ้นอย่างมากในบางกรณีหากโปรแกรมที่สร้างสตริงจำนวนมากที่จะไม่เปลี่ยนแปลงให้คัดลอก "ถัดไป ตัวชี้การจัดสรรสตริง "ไปที่ตัวชี้" ด้านบนของพื้นที่สตริง " การเปลี่ยนแปลงดังกล่าวจะป้องกันไม่ให้ตัวรวบรวมขยะทำการตรวจสอบสตริงเก่า ๆ เพื่อดูว่ายังจำเป็นหรือไม่ พลเรือจัตวา 64 นั้นแทบจะไม่ไฮเทค แต่ GC แบบ "generational" จะช่วยได้แม้กระทั่งที่นั่น
supercat

7

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

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


3

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


1

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

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


ฉันไม่แน่ใจว่ามีการใช้วิธีการเก็บรวบรวมขยะแบบใดใน minicomputers และเมนเฟรมเฟรมก่อนปลายปี 1970 แต่ตัวเก็บขยะ Microsoft BASIC อย่างน้อย 6502 เครื่องจะตั้งตัวชี้ "สตริงถัดไป" ไว้ที่ด้านบนของหน่วยความจำแล้วค้นหา การอ้างอิงสตริงทั้งหมดเพื่อค้นหาที่อยู่สูงสุดที่อยู่ด้านล่าง "ตัวชี้สตริงถัดไป" สตริงนั้นจะถูกคัดลอกใต้ "ตัวชี้สตริงถัดไป" และตัวชี้นั้นจะถูกจอดไว้ด้านล่าง อัลกอริทึมก็จะทำซ้ำ มันเป็นไปได้สำหรับรหัสที่จะนำโชคร้ายมาให้ ...
supercat

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

-2

โดยทั่วไป ... GC ใช้ "ที่เก็บข้อมูล" เพื่อแยกสิ่งที่ใช้งานอยู่ออกและสิ่งที่ไม่ได้ใช้ เมื่อทำการตรวจสอบแล้วมันจะทำการลบสิ่งที่ไม่ได้ใช้งานและย้ายทุกอย่างไปยังรุ่นที่ 2 (ซึ่งมีการตรวจสอบน้อยกว่ารุ่นที่ 1) จากนั้นย้ายสิ่งต่าง ๆ ที่ยังคงใช้งานอยู่ใน 2nd den to gen

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


1
แต่จะทราบได้อย่างไรว่ามีวัตถุใดที่ใช้งานอยู่
Pieter van Ginkel

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

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

@delnan ใช่ฉันกำลังตอบคำถามว่ามันรู้ว่ามีการใช้วัตถุใดซึ่งเป็นความคิดเห็นของปีเตอร์
JohnL

-5

อัลกอริทึมที่ใช้โดย GC นี้คือการทำเครื่องหมายและกวาด

คุณควรจะตระหนักถึงความจริงที่ว่านี้คือการไม่ได้รับการจัดการโดย C # ตัวเอง แต่โดยที่เรียกว่าCLR


นั่นคือความรู้สึกที่ฉันได้จากการอ่านเกี่ยวกับตัวเก็บขยะของโมโน อย่างไรก็ตามสิ่งที่ฉันไม่เข้าใจคือเหตุผลว่าทำไมพวกเขากำลังสแกนชุดการทำงานที่สมบูรณ์ในการสะสมพวกเขามีนักสะสม generational ที่สะสม GEN-0 ของเขาอย่างรวดเร็ว วิธีนี้จะเร็วด้วยชุดพูด 2GB?
Pieter van Ginkel

ดี GC จริงสำหรับขาวดำคือ Sgen คุณควรอ่านmono-project.com/Generational_GCนี้หรือบทความออนไลน์บางschani.wordpress.com/tag/mono infoq.com/news/2011/01/SGenประเด็นก็คือ เทคโนโลยีใหม่นี้เช่น CLR และ CLI มีการออกแบบแบบแยกส่วนจริงๆภาษากลายเป็นวิธีหนึ่งในการแสดงบางสิ่งบางอย่างสำหรับ CLR และไม่ใช่วิธีการสร้างรหัสไบนารี คำถามของคุณเกี่ยวกับรายละเอียดการใช้งานและไม่เกี่ยวกับอัลกอริธึมเนื่องจากอัลกอริทึมยังไม่มีการใช้งานคุณควรอ่านเอกสารทางเทคนิคและบทความจาก Mono ไม่ใช่คนอื่น
user827992

ฉันสับสน กลยุทธ์ที่ตัวรวบรวมขยะใช้ไม่ใช่อัลกอริทึมหรือไม่?
Pieter van Ginkel

2
-1 หยุด OP สับสน GC นั้นเป็นส่วนหนึ่งของ CLR และไม่ใช่เฉพาะภาษานั้นไม่เกี่ยวข้องเลย GC เป็นลักษณะส่วนใหญ่โดยวิธีการวางฮีปและกำหนดความสามารถในการเข้าถึงและส่วนหลังคือข้อมูลเกี่ยวกับอัลกอริธึมที่ใช้สำหรับสิ่งนั้น แม้ว่าจะมีการใช้อัลกอริทึมมากมายและคุณไม่ควรพลาดรายละเอียดในการติดตั้ง แต่อัลกอริทึมจะกำหนดว่าจะสแกนวัตถุจำนวนเท่าใด generational GC เป็นเพียงอัลกอริทึม + โครงร่างฮีปที่พยายามใช้ "สมมติฐานทั่วไป" (วัตถุส่วนใหญ่ตายไปแล้ว) สิ่งเหล่านี้ไม่ไร้เดียงสา

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