กลับไปหน้าบทความ

อ่าน 10 นาที

การจัดการขยะ (วิทยาการคอมพิวเตอร์)

ใน วิทยาการคอมพิวเตอร์ การ เก็บขยะ ( GC ) เป็นรูปแบบหนึ่งของการจัดการหน่วยความจำอัตโนมัติ[ 2 ] ตัว เก็บ ขยะ พยายาม เรียกคืนหน่วยความจำที่โปรแกรมจัดสรรไว้...

การจัดการขยะ (วิทยาการคอมพิวเตอร์)

( เรียนรู้วิธีและเวลาในการลบข้อความนี้ )

การเก็บขยะแบบ Stop-and-copy ในสถาปัตยกรรม Lisp : [ 1 ]หน่วยความจำถูกแบ่งออกเป็น หน่วยความจำ ใช้งานและ หน่วยความจำ ว่างวัตถุใหม่จะถูกจัดสรรในหน่วยความจำใช้งาน เมื่อหน่วยความจำเต็ม (ดังภาพ) จะมีการดำเนินการเก็บขยะ: โครงสร้างข้อมูลทั้งหมดที่ยังคงใช้งานอยู่จะถูกค้นหาโดยการติดตามตัวชี้และคัดลอกไปยังตำแหน่งที่ต่อเนื่องกันในหน่วยความจำว่าง
หลังจากนั้น เนื้อหาในหน่วยความจำใช้งานจะถูกทิ้งไปเพื่อใช้สำเนาที่ถูกบีอัดแทน และบทบาทของ หน่วยความจำ ใช้งานและ หน่วยความจำ อิสระจะสลับกัน (ดังภาพ)

ในวิทยาการคอมพิวเตอร์การเก็บขยะ ( GC ) เป็นรูปแบบหนึ่งของการจัดการหน่วยความจำอัตโนมัติ[ 2 ]ตัวเก็บขยะพยายามเรียกคืนหน่วยความจำที่โปรแกรมจัดสรรไว้ แต่ไม่ได้ถูกอ้างอิงอีกต่อไป หน่วยความจำดังกล่าวเรียกว่าขยะการเก็บขยะถูกคิดค้นโดยนักวิทยาศาสตร์คอมพิวเตอร์ชาวอเมริกันJohn McCarthyประมาณปี 1959 เพื่อลดความซับซ้อนของการจัดการหน่วยความจำด้วยตนเองในภาษาLisp [ 3 ]

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

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

ภาพรวม

ภาษาโปรแกรมหลาย ภาษา จำเป็นต้องมีการเก็บขยะ ไม่ว่าจะเป็นส่วนหนึ่งของข้อกำหนดของภาษา (เช่นRPL , Java , C# , D , [ 4 ] Goและภาษาสคริปต์ ส่วนใหญ่ ) หรือเพื่อการใช้งานจริง (เช่น ภาษาทางการอย่างแคลคูลัสแลมบ์ดา ) [ 5 ] ภาษา เหล่านี้เรียกว่าภาษาที่มีการเก็บขยะภาษาอื่นๆ เช่นCและC++ถูกออกแบบมาเพื่อใช้กับการจัดการหน่วยความจำด้วยตนเอง แต่ก็มีการใช้งานที่มีการเก็บขยะให้เลือกใช้ ภาษาบางภาษา เช่นAda , Modula-3และC++/CLIอนุญาตให้ทั้งการเก็บขยะและการจัดการหน่วยความจำด้วยตนเองทำงานร่วมกันได้ในแอปพลิเคชันเดียวกัน โดยใช้ฮีป แยกต่างหาก สำหรับวัตถุที่ถูกเก็บขยะและวัตถุที่จัดการด้วยตนเอง ภาษาอื่นๆ เช่นDมีการเก็บขยะ แต่ผู้ใช้สามารถลบวัตถุด้วยตนเองหรือปิดใช้งานการเก็บขยะได้ทั้งหมดเมื่อต้องการความเร็ว[ 6 ]

แม้ว่าหลายภาษาจะรวม GC เข้ากับคอมไพเลอร์และระบบรันไทม์แต่ ก็ยังมีระบบ GC แบบ post-hocอยู่ เช่นAutomatic Reference Counting (ARC) ระบบ GC แบบ post-hocบางระบบไม่จำเป็นต้องคอมไพล์ใหม่[ 7 ]

ข้อดี

GC ช่วยให้โปรแกรมเมอร์ไม่ต้องยกเลิกการจัดสรรหน่วยความจำด้วยตนเอง ซึ่งจะช่วยหลีกเลี่ยงข้อผิดพลาด บางประเภทได้ : [ 8 ]

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

ข้อเสีย

GC ใช้ทรัพยากรการคำนวณเพื่อตัดสินใจว่าจะปล่อยหน่วยความจำใด ดังนั้น ค่าใช้จ่ายสำหรับความสะดวกสบายในการไม่ระบุอายุการใช้งานของวัตถุด้วยตนเองในซอร์สโค้ดคือโอเวอร์เฮดซึ่งอาจส่งผลเสียต่อประสิทธิภาพของโปรแกรม[ 11 ]บทความวิจัยที่ได้รับการตรวจสอบโดยผู้ทรงคุณวุฒิในปี 2548 สรุปว่า GC ต้องการหน่วยความจำมากกว่าถึงห้าเท่าเพื่อชดเชยโอเวอร์เฮดนี้และเพื่อให้ทำงานได้เร็วเท่ากับโปรแกรมเดียวกันที่ใช้การจัดการหน่วยความจำแบบชัดเจนในอุดมคติ อย่างไรก็ตาม การเปรียบเทียบนี้ทำกับโปรแกรมที่สร้างขึ้นโดยการแทรกการเรียกยกเลิกการจัดสรรโดยใช้ออราเคิลซึ่งดำเนินการโดยการรวบรวมร่องรอยจากโปรแกรมที่ทำงานภายใต้โปรไฟล์เลอร์และโปรแกรมนั้นถูกต้องเฉพาะสำหรับการดำเนินการโปรแกรมครั้งใดครั้งหนึ่งเท่านั้น[ 12 ]ปฏิสัมพันธ์กับ เอฟเฟกต์ ลำดับชั้นของหน่วยความจำอาจทำให้โอเวอร์เฮดนี้ทนไม่ได้ในสถานการณ์ที่ยากต่อการคาดการณ์หรือตรวจจับในการทดสอบตามปกติ ผลกระทบต่อประสิทธิภาพนี้ถูกอ้างโดย Apple ว่าเป็นเหตุผลที่ไม่นำการเก็บขยะมาใช้ในiOSแม้ว่าจะเป็นคุณสมบัติที่ต้องการมากที่สุดก็ตาม[ 13 ]

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

กลยุทธ์

การติดตาม

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

การนับอ้างอิง

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

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

การนับจำนวนการอ้างอิงมีข้อเสียอยู่หลายประการ ซึ่งโดยทั่วไปแล้วสามารถแก้ไขหรือลดผลกระทบได้ด้วยอัลกอริธึมที่ซับซ้อนกว่า:

วงจร
หากวัตถุสองชิ้นขึ้นไปอ้างอิงถึงกันและกัน วัตถุเหล่านั้นอาจสร้างวงจรขึ้นมา ซึ่งจะทำให้ไม่มีวัตถุใดถูกเก็บรวบรวม เนื่องจากการอ้างอิงซึ่งกันและกันจะไม่ทำให้จำนวนการอ้างอิงกลายเป็นศูนย์ ระบบการเก็บขยะบางระบบที่ใช้การนับการอ้างอิง (เช่น ระบบในCPython ) ใช้ขั้นตอนวิธีตรวจจับวงจรเฉพาะเพื่อจัดการกับปัญหานี้[ 16 ]กลยุทธ์อีกอย่างหนึ่งคือการใช้การอ้างอิงแบบอ่อนสำหรับ "backpointer" ซึ่งสร้างวงจร ภายใต้การนับการอ้างอิง การอ้างอิงแบบอ่อนจะคล้ายกับการอ้างอิงแบบอ่อนภายใต้ตัวเก็บขยะแบบติดตาม มันเป็นวัตถุอ้างอิงพิเศษที่การมีอยู่ของมันไม่ได้เพิ่มจำนวนการอ้างอิงของวัตถุที่ถูกอ้างอิง ยิ่งไปกว่านั้น การอ้างอิงแบบอ่อนมีความปลอดภัยตรงที่เมื่อวัตถุที่ถูกอ้างอิงกลายเป็นขยะ การอ้างอิงแบบอ่อนใดๆ ก็ตามจะหมดอายุลงแทนที่จะได้รับอนุญาตให้คงอยู่แบบค้างอยู่ ซึ่งหมายความว่ามันจะกลายเป็นค่าที่คาดเดาได้ เช่น การอ้างอิงที่เป็นค่าว่าง
ค่าใช้จ่ายด้านพื้นที่ (จำนวนการอ้างอิง)
การนับการอ้างอิง (Reference counting) จำเป็นต้องจัดสรรพื้นที่สำหรับแต่ละอ็อบเจ็กต์เพื่อเก็บจำนวนการอ้างอิง จำนวนการอ้างอิงอาจถูกเก็บไว้ใกล้กับหน่วยความจำของอ็อบเจ็กต์หรือในตารางด้านข้างที่อื่น แต่ไม่ว่าในกรณีใด ทุกอ็อบเจ็กต์ที่มีการนับการอ้างอิงจำเป็นต้องมีพื้นที่จัดเก็บเพิ่มเติมสำหรับจำนวนการอ้างอิง โดยทั่วไปจะใช้พื้นที่หน่วยความจำขนาดเท่ากับพอยเตอร์แบบไม่ระบุเครื่องหมาย (unsigned pointer) สำหรับงานนี้ ซึ่งหมายความว่าต้องจัดสรรพื้นที่จัดเก็บจำนวนการอ้างอิง 32 หรือ 64 บิตสำหรับแต่ละอ็อบเจ็กต์ ในบางระบบ อาจสามารถลดภาระนี้ได้โดยใช้พอยเตอร์แบบแท็ก (tagged pointer)เพื่อเก็บจำนวนการอ้างอิงในพื้นที่ที่ไม่ได้ใช้งานของหน่วยความจำของอ็อบเจ็กต์ บ่อยครั้งที่สถาปัตยกรรมไม่อนุญาตให้โปรแกรมเข้าถึงช่วงของที่อยู่หน่วยความจำทั้งหมดที่สามารถจัดเก็บได้ในขนาดพอยเตอร์ดั้งเดิม บิตสูงจำนวนหนึ่งในที่อยู่จะถูกละเลยหรือต้องเป็นศูนย์ หากอ็อบเจ็กต์มีพอยเตอร์อยู่ที่ตำแหน่งใดตำแหน่งหนึ่งอย่างน่าเชื่อถือ จำนวนการอ้างอิงสามารถเก็บไว้ในบิตที่ไม่ได้ใช้งานของพอยเตอร์ได้ ตัวอย่างเช่น แต่ละอ็อบเจ็กต์ในObjective-Cมีพอยเตอร์ไปยังคลาส ของมัน ที่จุดเริ่มต้นของหน่วยความจำ บนสถาปัตยกรรมARM64 ที่ใช้ iOS 7บิตที่ไม่ได้ใช้ 19 บิตของตัวชี้คลาสนี้ถูกใช้เพื่อเก็บจำนวนการอ้างอิงของวัตถุ[ 17 ] [ 18 ]
ค่าใช้จ่ายเพิ่มเติมด้านความเร็ว (เพิ่ม/ลด)
ในการใช้งานแบบง่ายๆ การกำหนดค่าอ้างอิงแต่ละครั้งและการอ้างอิงแต่ละครั้งที่อยู่นอกขอบเขตมักต้องมีการแก้ไขตัวนับการอ้างอิงอย่างน้อยหนึ่งตัว อย่างไรก็ตาม ในกรณีทั่วไป เมื่อมีการคัดลอกการอ้างอิงจากตัวแปรขอบเขตภายนอกไปยังตัวแปรขอบเขตภายใน โดยที่อายุการใช้งานของตัวแปรภายในถูกจำกัดด้วยอายุการใช้งานของตัวแปรภายนอก การเพิ่มการอ้างอิงสามารถถูกกำจัดได้ ตัวแปรภายนอก "เป็นเจ้าของ" การอ้างอิง ในภาษาโปรแกรม C++ เทคนิคนี้ถูกนำไปใช้และสาธิตได้อย่างง่ายดายโดยใช้constการอ้างอิง การนับการอ้างอิงใน C++ มักจะถูกนำไปใช้โดยใช้ " ตัวชี้อัจฉริยะ " [ 19 ]ซึ่งตัวสร้าง ตัวทำลาย และตัวดำเนินการกำหนดค่าจะจัดการการอ้างอิง ตัวชี้อัจฉริยะสามารถส่งผ่านโดยการอ้างอิงไปยังฟังก์ชัน ซึ่งหลีกเลี่ยงความจำเป็นในการสร้างตัวชี้อัจฉริยะใหม่ (ซึ่งจะเพิ่มจำนวนการอ้างอิงเมื่อเข้าสู่ฟังก์ชันและลดลงเมื่อออก) แทนที่จะเป็นเช่นนั้น ฟังก์ชันจะได้รับการอ้างอิงไปยังตัวชี้อัจฉริยะซึ่งสร้างขึ้นอย่างประหยัด วิธีการนับการอ้างอิงแบบ Deutsch-Bobrow ใช้ประโยชน์จากข้อเท็จจริงที่ว่าการอัปเดตการนับการอ้างอิงส่วนใหญ่ถูกสร้างขึ้นโดยการอ้างอิงที่เก็บไว้ในตัวแปรโลคอล โดยจะละเว้นการอ้างอิงเหล่านี้ และนับเฉพาะการอ้างอิงในฮีปเท่านั้น แต่ก่อนที่จะลบวัตถุที่มีการนับการอ้างอิงเป็นศูนย์ ระบบจะต้องตรวจสอบด้วยการสแกนสแต็กและรีจิสเตอร์ว่าไม่มีการอ้างอิงอื่นใดที่ยังคงอยู่ การลดโอเวอร์เฮดในการอัปเดตตัวนับลงอย่างมากสามารถทำได้โดยการรวมการอัปเดตที่ Levanoni และPetrank นำ เสนอ[ 20 ] [ 21 ]พิจารณาพอยเตอร์ที่ได้รับการอัปเดตหลายครั้งในช่วงเวลาการทำงานที่กำหนด โดยจะชี้ไปยังวัตถุO1จากนั้นไปยังวัตถุO2และอื่นๆ จนกระทั่งเมื่อสิ้นสุดช่วงเวลาจะชี้ไปยังวัตถุบางอย่าง โดยOnทั่วไปแล้วอัลกอริทึมการนับการอ้างอิงจะดำเนินการrc(O1)--, rc(O2)++, rc(O2)--, rc(O3)++, rc(O3)--, ..., แต่การอัปเดตส่วนใหญ่เหล่านี้ซ้ำซ้อน เพื่อให้การนับการอ้างอิงได้รับการประเมินอย่างถูกต้องเมื่อสิ้นสุดช่วงเวลา การดำเนินการ และrc(On)++ก็เพียงพอแล้ว Levanoni และ Petrank วัดได้ว่าการอัปเดตตัวนับในเกณฑ์มาตรฐาน Java ทั่วไปลดลงมากกว่า 99%rc(O1)--rc(On)++
ต้องใช้ความเป็นอะตอม
เมื่อใช้งานใน สภาพแวดล้อม แบบมัลติเธรดการแก้ไขเหล่านี้ (การเพิ่มและการลดค่า) อาจจำเป็นต้องเป็นการดำเนินการอะตอมิกเช่นการเปรียบเทียบและการสลับอย่างน้อยสำหรับวัตถุใดๆ ที่ใช้ร่วมกัน หรืออาจใช้ร่วมกันระหว่างหลายเธรด การดำเนินการอะตอมิกมีค่าใช้จ่ายสูงในระบบมัลติโปรเซสเซอร์ และมีค่าใช้จ่ายสูงขึ้นไปอีกหากต้องจำลองด้วยอัลกอริธึมซอฟต์แวร์ เป็นไปได้ที่จะหลีกเลี่ยงปัญหานี้โดยการเพิ่มจำนวนการอ้างอิงต่อเธรดหรือต่อ CPU และเข้าถึงจำนวนการอ้างอิงทั่วโลกเฉพาะเมื่อจำนวนการอ้างอิงในพื้นที่กลายเป็นศูนย์หรือไม่เป็นศูนย์อีกต่อไป (หรืออีกทางเลือกหนึ่งคือการใช้ต้นไม้ไบนารีของจำนวนการอ้างอิง หรือแม้กระทั่งการละทิ้งการทำลายแบบกำหนดได้เพื่อแลกกับการไม่มีจำนวนการอ้างอิงทั่วโลกเลย) แต่สิ่งนี้จะเพิ่มภาระหน่วยความจำอย่างมากและมักจะมีประโยชน์เฉพาะในกรณีพิเศษเท่านั้น (ตัวอย่างเช่น ใช้ในการนับการอ้างอิงของโมดูลเคอร์เนล Linux) การรวมการอัปเดตโดย Levanoni และ Petrank [ 20 ] [ 21 ]สามารถใช้เพื่อกำจัดการดำเนินการอะตอมิกทั้งหมดออกจาก write-barrier ได้ ตัวนับจะไม่ได้รับการอัปเดตโดยเธรดของโปรแกรมในระหว่างการทำงานของโปรแกรม ตัวนับจะถูกแก้ไขโดยตัวเก็บรวบรวมเท่านั้น ซึ่งทำงานเสมือนเป็นเธรดเพิ่มเติมเพียงเธรดเดียวโดยไม่มีการซิงโครไนซ์ วิธีนี้สามารถใช้เป็นกลไกหยุดการทำงานทั้งหมดสำหรับโปรแกรมแบบขนาน และยังสามารถใช้กับตัวเก็บรวบรวมการนับอ้างอิงแบบพร้อมกันได้อีกด้วย
ไม่ใช่แบบเรียลไทม์
การใช้งานการนับการอ้างอิงแบบพื้นฐานมักไม่สามารถทำงานแบบเรียลไทม์ได้ เนื่องจาก1 การกำหนดค่าตัวชี้ใดๆ อาจทำให้วัตถุจำนวนหนึ่งซึ่งจำกัดด้วยขนาดหน่วยความจำที่จัดสรรไว้ทั้งหมดถูกปล่อยให้ว่างซ้ำๆ ในขณะที่เธรดไม่สามารถทำงานอื่นๆ ได้ สามารถหลีกเลี่ยงปัญหานี้ได้โดยการมอบหมายให้เธรดอื่นปล่อยวัตถุที่ไม่มีการอ้างอิง แต่ก็ต้องแลกมาด้วยค่าใช้จ่ายเพิ่มเติม

การวิเคราะห์การหลบหนี

การวิเคราะห์การหลุดรอด (Escape analysis)เป็นเทคนิคในระหว่างการคอมไพล์ที่สามารถแปลงการจัดสรรฮีปเป็นการจัดสรรสแต็กซึ่งจะช่วยลดปริมาณการเก็บขยะ (garbage collection) การวิเคราะห์นี้จะตรวจสอบว่าวัตถุที่จัดสรรภายในฟังก์ชันสามารถเข้าถึงได้จากภายนอกหรือไม่ หากพบว่าการจัดสรรภายในฟังก์ชันสามารถเข้าถึงได้จากฟังก์ชันหรือเธรดอื่น การจัดสรรนั้นจะเรียกว่า "หลุดรอด" (escape) และไม่สามารถทำบนสแต็กได้ มิฉะนั้น วัตถุอาจถูกจัดสรรโดยตรงบนสแต็กและปล่อยเมื่อฟังก์ชันส่งคืนค่า โดยข้ามฮีปและค่าใช้จ่ายในการจัดการหน่วยความจำที่เกี่ยวข้อง[ 22 ]

ความพร้อมใช้งาน

โดยทั่วไปแล้วภาษาโปรแกรมระดับสูงมักจะมีระบบจัดการขยะ (garbage collection) เป็นคุณสมบัติมาตรฐาน ในบางภาษาที่ไม่มีระบบจัดการขยะในตัว ก็สามารถเพิ่มเข้าไปได้ผ่านไลบรารี เช่นเดียวกับตัวจัดการขยะ Boehmสำหรับภาษา C และ C++

ภาษาการเขียนโปรแกรมเชิงฟังก์ชันส่วนใหญ่เช่นML , HaskellและAPLมีการเก็บขยะในตัวLispโดดเด่นเป็นพิเศษในฐานะที่เป็นภาษาการเขียนโปรแกรมเชิงฟังก์ชัน ภาษาแรก และเป็นภาษาแรกที่แนะนำการเก็บขยะ[ 23 ]

ภาษาแบบไดนามิกอื่นๆ เช่นRubyและJulia (แต่ไม่ใช่Perl  5 หรือPHPก่อนเวอร์ชัน 5.3 [ 24 ]ซึ่งทั้งสองใช้การนับการอ้างอิง) JavaScriptและECMAScriptก็มีแนวโน้มที่จะใช้ GC เช่นกัน ภาษา การเขียนโปรแกรมเชิงวัตถุเช่นSmalltalk , ooRexx , RPLและJavaมักจะมีระบบเก็บขยะในตัว ข้อยกเว้นที่สำคัญคือC++และDelphiซึ่งมีตัวทำลาย

พื้นฐาน

BASICและLogoมักใช้การเก็บขยะสำหรับชนิดข้อมูลที่มีความยาวแปรผัน เช่น สตริงและลิสต์ เพื่อไม่ให้โปรแกรมเมอร์ต้องแบกรับภาระกับรายละเอียดการจัดการหน่วยความจำ บนAltair 8800โปรแกรมที่มีตัวแปรสตริงจำนวนมากและพื้นที่สตริงน้อยอาจทำให้เกิดการหยุดชั่วคราวเป็นเวลานานเนื่องจากการเก็บขยะ[ 25 ]ในทำนองเดียวกัน อัลกอริทึมการเก็บขยะของตัวแปลภาษา Applesoft BASICจะสแกนตัวอธิบายสตริงซ้ำๆ เพื่อหาสตริงที่มีที่อยู่สูงสุดเพื่อบีบอัดไปยังหน่วยความจำส่วนบน ส่งผลให้ประสิทธิภาพ ลดลง [ 26 ]และหยุดชั่วคราวตั้งแต่ไม่กี่วินาทีถึงไม่กี่นาที[ 27 ]ตัวเก็บขยะทดแทนสำหรับ Applesoft BASIC โดยRandy Wiggintonจะระบุกลุ่มของสตริงในทุกรอบของฮีป ลดเวลาการเก็บขยะลงอย่างมาก[ 28 ] BASIC.SYSTEM ซึ่งเปิดตัวพร้อมกับProDOSในปี 1983 มีตัวเก็บขยะแบบหน้าต่างสำหรับ BASIC ที่เร็วกว่าหลายเท่า[ 29 ]

ซี และ ซี++

ภาษา Cไม่เคยให้การสนับสนุนอย่างเป็นทางการสำหรับการเก็บขยะภาษา C++เพิ่มการสนับสนุนการเก็บขยะในไลบรารีมาตรฐาน ใน C++11 แต่ถูกลบออกใน C++23เนื่องจากไม่มีคอมไพเลอร์ใดที่รองรับฟีเจอร์นี้[ 30 ]ฟีเจอร์ที่เป็นส่วนหนึ่งของสิ่งนี้เกี่ยวข้องกับความปลอดภัยของตัวชี้[ 31 ]

แม้ว่าการสนับสนุนการจัดการขยะในไลบรารีมาตรฐานจะถูกลบออกไปแล้ว แต่ตัวจัดการขยะบางตัว เช่นตัวจัดการขยะ Boehm (สำหรับ C และ C++) ยังคงสามารถใช้งานได้ ตัวจัดการขยะ Boehm ใช้การจัดการขยะแบบ mark-and-sweepนอกจากนี้ยังสามารถใช้งานในโหมดตรวจจับการรั่วไหลได้ ซึ่งการจัดการหน่วยความจำยังคงเป็นแบบแมนนวล แต่สามารถตรวจจับและรายงานการรั่วไหลและข้อผิดพลาด double-free ได้ สามารถเรียกใช้งานจากไฟล์เฮดเดอร์<gc.h>ได้

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

ออบเจกทีฟซี

แม้ว่าObjective-Cจะไม่มีการเก็บขยะ (garbage collection) ตามธรรมเนียม แต่เมื่อมีการเปิดตัวOS X 10.5ในปี 2007 Appleได้นำการเก็บขยะมาใช้กับObjective-C  2.0 โดยใช้ตัวเก็บรวบรวมรันไทม์ที่พัฒนาขึ้นเอง[ 32 ] อย่างไรก็ตาม เมื่อมีการเปิดตัวOS X 10.8 ในปี 2012 การเก็บขยะถูกยกเลิกและแทนที่ด้วยตัวนับการอ้างอิงอัตโนมัติ (ARC) ของLLVMที่เปิดตัวพร้อมกับOS X 10.7 [ 33 ] นอกจากนี้ ตั้งแต่เดือนพฤษภาคม 2015 Apple ยังห้ามการใช้การเก็บขยะสำหรับแอปพลิเคชัน OS X ใหม่ในApp Store อีกด้วย [ 34 ] [ 35 ]สำหรับiOSการเก็บขยะไม่เคยถูกนำมาใช้เนื่องจากปัญหาในการตอบสนองและประสิทธิภาพของแอปพลิเคชัน[ 13 ] [ 36 ]แต่ iOS ใช้ ARC แทน[ 37 ] [ 38 ]

สภาพแวดล้อมที่จำกัด

การเก็บขยะมักไม่ค่อยได้ใช้ใน ระบบ ฝังตัวหรือระบบเรียลไทม์ เนื่องจากโดยปกติแล้วจำเป็นต้องควบคุมการใช้ทรัพยากรที่มีจำกัดอย่างเข้มงวดมาก อย่างไรก็ตาม ได้มีการพัฒนาระบบเก็บขยะที่เข้ากันได้กับสภาพแวดล้อมที่มีข้อจำกัดหลายอย่าง[ 39 ] Microsoft .NET Micro Framework , .NET nanoFramework [ 40 ]และJava Platform, Micro Editionเป็นแพลตฟอร์มซอฟต์แวร์ฝังตัว ซึ่งเช่นเดียวกับแพลตฟอร์มขนาดใหญ่กว่า ก็มีการเก็บขยะรวมอยู่ด้วย

ชวา

ตัวจัดการขยะ (Garbage collector) ที่มีอยู่ในเครื่องเสมือน (JVM) ของ Java OpenJDK ได้แก่:

  • ซีเรียล
  • ขนาน
  • CMS (Concurrent Mark Sweep)
  • G1 (ระบบจัดการขยะแบบเริ่มต้นก่อน)
  • ZGC (ตัวเก็บขยะ Z)
  • เอปซิลอน
  • เชนันโดอาห์
  • GenZGC (Generational ZGC)
  • เก็นเชิน (เชนนันโดอาห์รุ่นต่อรุ่น)
  • เครื่องจับจังหวะของ IBM (มีเฉพาะในIBM OpenJDK)
  • SAP (เฉพาะในSAP OpenJDK)
  • Azul C4 (Continuously Concurrent Compacting Collector) [ 41 ] (เฉพาะในAzul Systems OpenJDK)

การใช้งานระหว่างการคอมไพล์

การจัดการหน่วยความจำอัตโนมัติในระหว่างการคอมไพล์ (Compile-time garbage collection) เป็นรูปแบบหนึ่งของการวิเคราะห์แบบคงที่ (Static analysis)ที่อนุญาตให้ใช้หน่วยความจำซ้ำและเรียกคืนหน่วยความจำได้โดยอิงตามเงื่อนไขที่ทราบในระหว่างการคอมไพล์

รูปแบบการเก็บขยะนี้ได้รับการศึกษาใน ภาษาการ เขียนโปรแกรม Mercury [ 42 ]และมีการใช้งานมากขึ้นเมื่อมีการนำตัวนับการอ้างอิงอัตโนมัติ (ARC) ของLLVMเข้าสู่ระบบนิเวศของ Apple (iOS และ OS X) ในปี 2011 [ 37 ] [ 38 ] [ 34 ]

ระบบเรียลไทม์

ตัวเก็บขยะแบบเพิ่มทีละน้อย แบบพร้อมกัน และแบบเรียลไทม์ได้รับการพัฒนาขึ้น ตัวอย่างเช่น โดยHenry BakerและHenry Lieberman [ 43 ] [ 44 ] [ 45 ]

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

ระบบ การเก็บขยะแบบแบ่งตามรุ่นอายุ (Generational garbage collection) อิงตามข้อสังเกตเชิงประจักษ์ที่ว่าวัตถุส่วนใหญ่มีอายุสั้น ในระบบนี้ จะมีการจัดเก็บพื้นที่จัดสรร (รุ่นอายุ) สองพื้นที่ขึ้นไป ซึ่งแยกออกจากกันตามอายุของวัตถุ วัตถุใหม่จะถูกสร้างขึ้นในรุ่นอายุ "ใหม่" ซึ่งจะถูกเก็บขยะเป็นประจำ และเมื่อรุ่นอายุหนึ่งเต็ม วัตถุที่ยังคงถูกอ้างอิงจากพื้นที่เก่ากว่าจะถูกคัดลอกไปยังรุ่นอายุถัดไปที่เก่ากว่า บางครั้งอาจมีการสแกนพื้นที่ทั้งหมด (full scan) ด้วย

สถาปัตยกรรมคอมพิวเตอร์สำหรับภาษาโปรแกรมระดับสูงบางแบบมีการรองรับฮาร์ดแวร์สำหรับการจัดการหน่วยความจำแบบเรียลไทม์

การใช้งานตัวเก็บขยะแบบเรียลไทม์ส่วนใหญ่ใช้การติดตามตัวเก็บขยะแบบเรียลไทม์ดังกล่าวตรงตาม ข้อจำกัด แบบเรียลไทม์ที่เข้มงวดเมื่อใช้กับระบบปฏิบัติการแบบเรียลไทม์[ 47 ]

ดูเพิ่มเติม

อ่านเพิ่มเติม

  • Jones, Richard; Hosking, Antony; Moss, J. Eliot B. (16 สิงหาคม 2554). คู่มือการจัดการหน่วยความจำอัตโนมัติ: ศิลปะแห่งการจัดการหน่วยความจำอัตโนมัติชุด CRC Applied Algorithms and Data Structures. Chapman and Hall / CRC Press / Taylor & Francis Ltd. ISBN 978-1-4200-8279-1.(511 หน้า)
  • โจนส์, ริชาร์ด; ลินส์, ราฟาเอล (12 กรกฎาคม 1996). การเก็บขยะ: อัลกอริทึมสำหรับการจัดการหน่วยความจำแบบไดนามิกอัตโนมัติ (ฉบับที่ 1). ไวลีย์ . ISBN 978-0-47194148-4.(404 หน้า)
  • Schorr, Herbert; Waite, William M. (สิงหาคม 1967). "ขั้นตอนที่มีประสิทธิภาพที่ไม่ขึ้นกับเครื่องจักรสำหรับการเก็บขยะในโครงสร้างรายการต่างๆ" (PDF) . Communications of the ACM . 10 (8): 501– 506. doi : 10.1145/363534.363554 . S2CID  5684388 . เก็บถาวร(PDF)จากต้นฉบับเมื่อ 2021-01-22.
  • วิลสัน, พอล อาร์. ( 1992). " เทคนิคการเก็บขยะของโปรเซสเซอร์เดี่ยว" การจัดการหน่วยความจำบันทึกการบรรยายในวิทยาการคอมพิวเตอร์ เล่มที่ 637 สปริงเกอร์-เวอร์แลกหน้า  1–42 CiteSeerX  10.1.1.47.2438 doi : 10.1007/bfb0017182 ISBN 3-540-55940-X.{{cite book}}: |journal=ละเลย ( ช่วยเหลือ )
  • วิลสัน, พอล อาร์.; จอห์นสโตน, มาร์ค เอส.; นีลี, ไมเคิล; โบเลส, เดวิด (1995). "การจัดสรรพื้นที่จัดเก็บข้อมูลแบบไดนามิก: การสำรวจและการวิเคราะห์เชิงวิพากษ์" การจัดการหน่วยความจำบันทึกการบรรยายในวิทยาการคอมพิวเตอร์ เล่มที่ 986 (ฉบับที่ 1). หน้า  1–116 . CiteSeerX  10.1.1.47.275 . doi : 10.1007/3-540-60368-9_19 . ISBN 978-3-540-60368-9.{{cite book}}: |journal=ละเลย ( ช่วยเหลือ )
  • เอกสารอ้างอิงการจัดการหน่วยความจำถูกเก็บถาวรเมื่อวันที่ 13 ธันวาคม 2020 ที่Wayback Machine
  • หลักการพื้นฐานที่สุดของการเก็บขยะ
  • การปรับแต่งการจัดการขยะของเครื่องเสมือน HotSpot ใน Java SE 6
  • TinyGC - การใช้งาน API ของ BoehmGC อย่างอิสระ
  • การนำระบบเก็บขยะแบบอนุรักษ์นิยมมาใช้ในภาษาซี
  • MeixnerGC - ตัวเก็บขยะแบบเพิ่มทีละขั้น (incremental mark and sweep) สำหรับ C++ ที่ใช้ตัวชี้อัจฉริยะ (smart pointers)
ดึงข้อมูลมาจาก " https://en.wikipedia.org/w/index.php?title=Garbage_collection_(computer_science)&oldid=1350516691 "

สรุปเนื้อหา

ข้อมูลสำคัญจากบทความ

ข้อมูลสำคัญเกี่ยวกับ การจัดการขยะ (วิทยาการคอมพิวเตอร์)

ใน วิทยาการคอมพิวเตอร์ การ เก็บขยะ ( GC ) เป็นรูปแบบหนึ่งของการจัดการหน่วยความจำอัตโนมัติ[ 2 ] ตัว เก็บ ขยะ พยายาม เรียกคืนหน่วยความจำที่โปรแกรมจัดสรรไว้...

ภาพรวม

ภาษาโปรแกรม หลาย ภาษา จำเป็นต้องมีการเก็บขยะ ไม่ว่าจะเป็นส่วนหนึ่งของ ข้อกำหนดของภาษา (เช่น RPL , Java , C# , D , [ 4 ] Go และ ภาษาสคริปต์ ส่วนใหญ่ ) หรือเพื่อการใช้งานจริง (เช่น ภาษาทางการอย่าง แคลคูลัสแลมบ์ดา ) [ 5 ] ภาษา เหล่านี้เรียกว่า...

ข้อดี

GC ช่วยให้โปรแกรมเมอร์ไม่ต้องยกเลิกการจัดสรรหน่วยความจำด้วยตนเอง ซึ่งจะช่วยหลีกเลี่ยง ข้อผิดพลาด บางประเภทได้ : [ 8 ]

ข้อเสีย

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