นี่คือเวอร์ชัน 8.3.0 (การพัฒนารุ่นถัดไป) ของตัวรวบรวมขยะแบบอนุรักษ์นิยมสำหรับ C และ C++
ใบอนุญาต: สไตล์ MIT
คุณอาจพบเวอร์ชันล่าสุด/เสถียรกว่าในหน้าดาวน์โหลดหรือไซต์ BDWGC
นอกจากนี้ การแก้ไขข้อบกพร่องล่าสุดและฟีเจอร์ใหม่ๆ ยังมีให้ใช้งานในพื้นที่เก็บข้อมูลการพัฒนาอีกด้วย
มีวัตถุประสงค์เพื่อวัตถุประสงค์ทั่วไปในการจัดสรรพื้นที่เก็บขยะ อัลกอริธึมที่ใช้อธิบายไว้ใน:
Boehm, H. และ M. Weiser, "Garbage Collection in an Uncooperative Environment", Software Practice & Experience, กันยายน 1988, หน้า 807-820
Boehm, H., A. Demers และ S. Shenker, "Mostly Parallel Garbage Collection", การดำเนินการของการประชุม ACM SIGPLAN '91 เกี่ยวกับการออกแบบและการปรับใช้ภาษาโปรแกรม, ประกาศ SIGPLAN 26, 6 (มิถุนายน 1991), หน้า 157- 164.
Boehm, H., "Space Efficient Conservative Garbage Collection", การดำเนินการของการประชุม ACM SIGPLAN '91 เรื่องการออกแบบและการปรับใช้ภาษาโปรแกรม, ประกาศ SIGPLAN 28, 6 (มิถุนายน 1993), หน้า 197-206
Boehm H., "การลดแคชตัวรวบรวมขยะ", การดำเนินการของการประชุมวิชาการนานาชาติเรื่องการจัดการหน่วยความจำประจำปี 2000
มีการพูดคุยถึงการโต้ตอบที่เป็นไปได้ระหว่างตัวรวบรวมและคอมไพเลอร์ที่ปรับให้เหมาะสม
Boehm, H. และ D. Chase, "ข้อเสนอสำหรับการรวบรวม C ที่ปลอดภัยของ GC", The Journal of C Language Translation 4, 2 (ธันวาคม 1992)
Boehm H., "Simple GC-safe Compilation", การประชุม ACM SIGPLAN '96 Conference on Programming Language Design and Implementation
แตกต่างจากตัวรวบรวมที่อธิบายไว้ในการอ้างอิงครั้งที่สอง ตัวรวบรวมนี้ทำงานโดยที่ mutator หยุดทำงานระหว่างการรวบรวมทั้งหมด (ค่าเริ่มต้น) หรือเพิ่มขึ้นระหว่างการจัดสรร (อย่างหลังรองรับบนเครื่องจำนวนน้อยกว่า) บนแพลตฟอร์มทั่วไปส่วนใหญ่ สามารถสร้างโดยมีหรือไม่มีการรองรับเธรดก็ได้ ในบางแพลตฟอร์ม สามารถใช้ประโยชน์จากมัลติโปรเซสเซอร์เพื่อเร่งการรวบรวมขยะ
แนวคิดหลายประการที่เป็นรากฐานของนักสะสมนั้นเคยถูกผู้อื่นสำรวจมาก่อน โดยเฉพาะอย่างยิ่ง ระบบรันไทม์บางระบบที่พัฒนาขึ้นที่ Xerox PARC ในช่วงต้นทศวรรษ 1980 ได้สแกนสแต็กเธรดอย่างระมัดระวังเพื่อค้นหาพอยน์เตอร์ที่เป็นไปได้ (เปรียบเทียบ Paul Rovner, "ในการเพิ่ม Garbage Collection และ Runtime Types ไปยัง Strongly-Typed Staically Checked, Concurrent Language" ซีร็อกซ์ PARC CSL 84-7) Doug McIlroy เขียนตัวสะสมแบบอนุรักษ์นิยมที่เรียบง่ายกว่าซึ่งเป็นส่วนหนึ่งของเวอร์ชัน 8 UNIX (tm) แต่ดูเหมือนว่าจะไม่ได้รับการใช้อย่างแพร่หลาย
มีเครื่องมือพื้นฐานสำหรับการใช้ตัวรวบรวมเป็นเครื่องตรวจจับการรั่วไหลรวมอยู่ด้วย เช่นเดียวกับ "สายไฟ" แพ็คเกจสตริงที่ค่อนข้างซับซ้อนซึ่งใช้ตัวรวบรวม (ดู README.cords และ H.-J. Boehm, R. Atkinson และ M. Plass, "Ropes: An Alternative to Strings", Software Practice and Experience 25, 12 (ธันวาคม 1995), หน้า 1315-1330 สิ่งนี้ คล้ายกับแพ็คเกจ "rope" ใน Xerox Cedar หรือแพ็คเกจ "rope" ใน SGI STL หรือการแจกแจง g++ มาก)
คุณสามารถดูเอกสารประกอบของผู้รวบรวมเพิ่มเติมได้ในภาพรวม
การใช้งานที่ทราบบางประการของตัวรวบรวมแสดงอยู่ในหน้าไคลเอ็นต์ที่รู้จักของ GitHub
นี่คือตัวจัดสรรหน่วยเก็บข้อมูลขยะที่มีวัตถุประสงค์เพื่อใช้แทนปลั๊กอินสำหรับ malloc ของ C
เนื่องจากตัวรวบรวมไม่จำเป็นต้องติดแท็กพอยน์เตอร์ จึงไม่พยายามให้แน่ใจว่าพื้นที่เก็บข้อมูลที่ไม่สามารถเข้าถึงได้ทั้งหมดจะถูกเรียกคืน อย่างไรก็ตาม จากประสบการณ์ของเรา โดยทั่วไปการเรียกคืนหน่วยความจำที่ไม่ได้ใช้จะประสบความสำเร็จมากกว่าโปรแกรม C ส่วนใหญ่ที่ใช้การจัดสรรคืนอย่างชัดเจน ต่างจากการรั่วไหลที่เกิดขึ้นด้วยตนเอง โดยทั่วไปปริมาณของหน่วยความจำที่ไม่ได้รับการเรียกคืนมักจะมีขอบเขตจำกัด
ต่อไปนี้ "อ็อบเจ็กต์" ถูกกำหนดให้เป็นขอบเขตของหน่วยความจำที่จัดสรรโดยรูทีนที่อธิบายไว้ด้านล่าง
อ็อบเจ็กต์ใดๆ ที่ไม่ได้ตั้งใจจะรวบรวมจะต้องชี้ไปที่จากอ็อบเจ็กต์ที่สามารถเข้าถึงได้อื่นๆ หรือจากรีจิสเตอร์ สแต็ก ข้อมูล หรือเซ็กเมนต์ bss ที่จัดสรรแบบคงที่ ตัวชี้จากสแต็กหรือรีจิสเตอร์อาจชี้ไปที่ใดก็ได้ภายในวัตถุ เช่นเดียวกับฮีปพอยน์เตอร์ หากตัวรวบรวมถูกคอมไพล์ด้วย ALL_INTERIOR_POINTERS
ที่กำหนด หรือ GC_all_interior_pointers
ถูกตั้งค่าเป็นอย่างอื่น ดังที่เป็นค่าเริ่มต้นในขณะนี้
การคอมไพล์โดยไม่มี ALL_INTERIOR_POINTERS
อาจลดการกักเก็บอ็อบเจ็กต์ขยะโดยไม่ตั้งใจ โดยกำหนดให้มีพอยน์เตอร์จากฮีปจนถึงจุดเริ่มต้นของอ็อบเจ็กต์ แต่ดูเหมือนจะไม่เป็นปัญหาสำคัญอีกต่อไปสำหรับโปรแกรมส่วนใหญ่ที่ใช้พื้นที่ที่อยู่ที่เป็นไปได้เพียงเล็กน้อย
มีกิจวัตรหลายอย่างที่ปรับเปลี่ยนอัลกอริธึมการรู้จำตัวชี้ GC_register_displacement
ช่วยให้สามารถจดจำตัวชี้ภายในบางตัวได้ แม้ว่าจะไม่ได้กำหนด ALL_INTERIOR_POINTERS
ไว้ก็ตาม GC_malloc_ignore_off_page
อนุญาตให้มองข้ามพอยน์เตอร์บางตัวที่อยู่ตรงกลางของออบเจ็กต์ขนาดใหญ่ ซึ่งช่วยลดโอกาสที่จะเก็บรักษาออบเจ็กต์ขนาดใหญ่โดยไม่ตั้งใจได้อย่างมาก สำหรับวัตถุประสงค์ส่วนใหญ่ วิธีที่ดีที่สุดคือคอมไพล์ด้วย ALL_INTERIOR_POINTERS
และใช้ GC_malloc_ignore_off_page
หากคุณได้รับคำเตือนจากตัวรวบรวมจากการจัดสรรอ็อบเจ็กต์ที่มีขนาดใหญ่มาก ดูรายละเอียดที่นี่
คำเตือน : ตัวชี้ภายในหน่วยความจำที่จัดสรรโดย malloc
มาตรฐาน (ระบบ) จะไม่ถูกมองเห็นโดยตัวรวบรวมขยะ ดังนั้นวัตถุที่ชี้ไปเฉพาะจากภูมิภาคดังกล่าวอาจถูกจัดสรรคืนก่อนกำหนด ดังนั้นจึงแนะนำว่าให้ใช้ malloc
มาตรฐานสำหรับขอบเขตหน่วยความจำเท่านั้น เช่น บัฟเฟอร์ I/O ที่รับประกันว่าจะไม่มีพอยน์เตอร์ไปยังหน่วยความจำสะสมขยะ พอยน์เตอร์ในตัวแปรอัตโนมัติ สแตติก หรือรีจิสเตอร์ในภาษา C ได้รับการยอมรับอย่างถูกต้อง (โปรดทราบว่า GC_malloc_uncollectable
มีความหมายคล้ายกับ malloc มาตรฐาน แต่จัดสรรอ็อบเจ็กต์ที่ติดตามโดยตัวรวบรวม)
คำเตือน : ตัวรวบรวมไม่ได้รู้วิธีค้นหาตัวชี้ในพื้นที่ข้อมูลที่เกี่ยวข้องกับไลบรารีแบบไดนามิกเสมอไป วิธีแก้ไขนี้ทำได้ง่ายหากคุณรู้วิธีค้นหาพื้นที่ข้อมูลเหล่านั้นในระบบปฏิบัติการของคุณ (ดู GC_add_roots
) รหัสสำหรับการดำเนินการนี้ภายใต้ SunOS, IRIX 5.X และ 6.X, HP/UX, Alpha OSF/1, Linux และ Win32 จะรวมอยู่และใช้เป็นค่าเริ่มต้น (ดูรายละเอียด README.win32 และ README.win64 สำหรับ Windows) ในระบบอื่น ตัวชี้จากพื้นที่ข้อมูลไลบรารีไดนามิกอาจไม่ได้รับการพิจารณาโดยตัวรวบรวม หากคุณกำลังเขียนโปรแกรมที่ขึ้นอยู่กับตัวรวบรวมที่สแกนพื้นที่ข้อมูลไลบรารีแบบไดนามิก อาจเป็นความคิดที่ดีที่จะรวมการเรียก GC_is_visible
อย่างน้อยหนึ่งครั้งเพื่อให้แน่ใจว่าตัวรวบรวมจะมองเห็นพื้นที่เหล่านั้นได้
โปรดทราบว่าตัวรวบรวมขยะไม่จำเป็นต้องได้รับแจ้งเกี่ยวกับข้อมูลที่แชร์แบบอ่านอย่างเดียว อย่างไรก็ตาม หากกลไกไลบรารีที่ใช้ร่วมกันสามารถแนะนำพื้นที่ข้อมูลที่ไม่ต่อเนื่องกันซึ่งอาจมีตัวชี้อยู่ ผู้รวบรวมก็ไม่จำเป็นต้องได้รับการแจ้ง
การประมวลผลสัญญาณสำหรับสัญญาณส่วนใหญ่อาจถูกเลื่อนออกไปในระหว่างการรวบรวม และในระหว่างกระบวนการจัดสรรส่วนที่ไม่หยุดชะงัก เช่นเดียวกับ ANSI C mallocs มาตรฐาน ตามค่าเริ่มต้น การเรียกใช้ malloc (และรูทีน GC อื่นๆ) จากตัวจัดการสัญญาณในขณะที่การเรียก malloc อื่นอาจดำเนินการอยู่นั้นไม่ปลอดภัย
ตัวจัดสรร/ตัวรวบรวมยังสามารถกำหนดค่าสำหรับการดำเนินการที่ปลอดภัยของเธรดได้ (ยังสามารถบรรลุความปลอดภัยของสัญญาณแบบเต็มได้ แต่ต้องเสียค่าใช้จ่ายของการเรียกระบบสองครั้งต่อ malloc เท่านั้น ซึ่งโดยปกติจะยอมรับไม่ได้)
คำเตือน : ตัวรวบรวมไม่รับประกันว่าจะสแกนที่เก็บข้อมูลภายในเธรด (เช่นชนิดที่เข้าถึงด้วย pthread_getspecific
) ตัวรวบรวมจะสแกนสแต็กของเธรด โดยทั่วไปแล้ว ทางออกที่ดีที่สุดคือตรวจสอบให้แน่ใจว่าตัวชี้ใดๆ ที่จัดเก็บไว้ในที่จัดเก็บภายในเธรดนั้นจะถูกจัดเก็บไว้ในสแต็กของเธรดตลอดอายุการใช้งาน (อาจเป็นข้อผิดพลาดที่มีมานาน แต่ยังไม่ได้รับการแก้ไข)
มีหลายวิธีในการสร้างตัวสะสม:
CMake (เป็นวิธีที่แนะนำ)
GNU ตั้งค่าอัตโนมัติ/สร้างอัตโนมัติ
ซิก (ทดลอง)
MS nmake (โดยตรง)
Makefile.direct
การรวบรวม C ด้วยตนเอง
วิธีที่ง่ายที่สุดในการสร้าง libgc (เช่นเดียวกับ libcord) และรันการทดสอบโดยใช้ cmake:
mkdir outcd ออก cmake -Dbuild_tests=เปิด .. cmake --build .ctest
นี่เป็นวิธีการสร้างห้องสมุดข้ามแพลตฟอร์มมากที่สุด ดู README.cmake สำหรับรายละเอียด
โปรดทราบว่าแหล่งเก็บข้อมูลต้นทางของตัวรวบรวมไม่มีไฟล์ configure
และไฟล์ที่สร้างขึ้นอัตโนมัติที่คล้ายกัน ดังนั้นขั้นตอนทั้งหมดของการสร้างตัวรวบรวมที่ใช้ autoconf จากแหล่งเก็บข้อมูลต้นทางอาจมีลักษณะดังนี้:
./autogen.sh ./กำหนดค่า ทำการตรวจสอบ
กระบวนการสร้างสไตล์ GNU เข้าใจเป้าหมายและตัวเลือกตามปกติ make install
การติดตั้ง libgc และ libcord ลอง ./configure --help
เพื่อดูตัวเลือกการกำหนดค่าทั้งหมด ขณะนี้ยังไม่สามารถใช้ตัวเลือกการสร้างทั้งหมดรวมกันด้วยวิธีนี้ได้
ดู README.autoconf สำหรับรายละเอียด
การสร้างและทดสอบตัวรวบรวมโดยใช้ zig นั้นตรงไปตรงมาในรูปแบบที่ง่ายที่สุด:
การทดสอบการสร้างซิก
เป็นไปได้ที่จะกำหนดค่าบิลด์ผ่านการใช้ตัวแปร เช่น zig build -Denable_redirect_malloc -Denable_threads=false
Zig มีฟังก์ชันการคอมไพล์ข้ามที่ยอดเยี่ยม โดยสามารถกำหนดค่าได้ดังนี้:
ซิกบิลด์ -Dtarget=riscv64-linux-musl
ปัจจุบันจำเป็นต้องมี zig 0.12 เวอร์ชันกลางคืน ซึ่งสามารถดาวน์โหลดได้จาก https://ziglang.org/download/
บน Windows สมมติว่ามีการติดตั้งเครื่องมือ Microsoft build และกำหนดค่าอย่างเหมาะสม ก็เป็นไปได้ที่จะสร้างไลบรารีและรันการทดสอบโดยใช้ nmake
โดยตรง เช่น โดยการพิมพ์ nmake -f NT_MAKEFILE check
อย่างไรก็ตาม วิธีที่แนะนำคือใช้ cmake ตามที่อธิบายไว้ข้างต้น
ดู README.win32 สำหรับรายละเอียด
สำหรับกระบวนการสร้างที่ใช้ makefile แบบเก่า (คลาสสิก) การพิมพ์ make -f Makefile.direct check
จะสร้าง libgc, libcord โดยอัตโนมัติ จากนั้นจึงเรียกใช้การทดสอบหลายอย่าง เช่น gctest
การทดสอบนี้เป็นการทดสอบการทำงานของตัวรวบรวมแบบผิวเผิน ความล้มเหลวจะถูกระบุโดยคอร์ดัมพ์หรือข้อความที่แจ้งว่าตัวรวบรวมใช้งานไม่ได้ gctest
อาจใช้เวลาหลายสิบวินาทีในการทำงานบนเดสก์ท็อปวินเทจ 64 บิตปี 2023 ที่สมเหตุสมผล อาจใช้หน่วยความจำสูงสุดประมาณ 30 MB
Makefile.direct จะสร้างไลบรารี libgc.a ซึ่งคุณควรเชื่อมโยงด้วย
สุดท้ายนี้ สำหรับเป้าหมายส่วนใหญ่ ตัวรวบรวมสามารถสร้างและทดสอบได้โดยตรงด้วยการเรียกใช้คอมไพลเลอร์ตัวเดียว เช่นนี้ (ตัวอย่างขาดการสนับสนุนแบบมัลติเธรด):
cc -ฉันรวม -o gctest tests/gctest.c extra/gc.c && ./gctest
เช่น อาจสะดวกสำหรับวัตถุประสงค์ในการแก้ไขจุดบกพร่อง
ไลบรารีสามารถกำหนดค่าได้แม่นยำยิ่งขึ้นในระหว่างการสร้างโดยการกำหนดมาโครที่แสดงอยู่ในไฟล์ README.macros
ไลบรารีถูกสร้างขึ้นโดยเปิดใช้งานการรองรับเธรด (เช่น สำหรับการดำเนินการที่ปลอดภัยสำหรับเธรด) โดยค่าเริ่มต้น เว้นแต่จะถูกปิดใช้งานอย่างชัดเจนโดย:
-Denable_threads=false
ตัวเลือกที่ส่งผ่านไปยัง cmake
หรือ zig build
--disable-threads
ตัวเลือกที่ส่งผ่านไปยัง ./configure
ตัวรวบรวมทำงานแบบเงียบๆ ในคอนฟิกูเรชันดีฟอลต์ ในกรณีที่เกิดปัญหา โดยปกติสามารถเปลี่ยนแปลงได้โดยการกำหนดตัวแปรสภาพแวดล้อม GC_PRINT_STATS
หรือ GC_PRINT_VERBOSE_STATS
ซึ่งจะส่งผลให้มีเอาต์พุตเชิงอธิบายสองสามบรรทัดสำหรับแต่ละคอลเลกชัน (สถิติที่ระบุมีลักษณะเฉพาะบางประการ สิ่งต่าง ๆ ดูเหมือนจะไม่รวมกันด้วยเหตุผลหลายประการ โดยเฉพาะอย่างยิ่งการสูญเสียการกระจายตัวที่สะดุดตา สิ่งเหล่านี้อาจมีความสำคัญมากกว่าสำหรับโปรแกรมที่วางแผนไว้ gctest
มากกว่าสำหรับแอปพลิเคชันของคุณ)
ขณะนี้การใช้ (การโคลน) ของ libatomic_ops
เป็นทางเลือกหากคอมไพลเลอร์รองรับอะตอมมิกอินทรินซิก คอมไพเลอร์สมัยใหม่ส่วนใหญ่ทำ ข้อยกเว้นที่น่าสังเกตคือคอมไพเลอร์ MS (ตั้งแต่ Visual Studio 2022)
หากจำเป็น ระบบปฏิบัติการส่วนใหญ่จะมีแพ็คเกจ libatomic_ops
หรือคุณสามารถดาวน์โหลดหรือโคลนได้จากhttps://github.com/ivmai/libatomic_ops space
ปัจจุบันตัวรวบรวมได้รับการออกแบบให้ทำงานโดยไม่มีการแก้ไขบนเครื่องที่ใช้พื้นที่ที่อยู่แบบแบน 32 บิตหรือ 64 บิต ซึ่งรวมถึงเวิร์คสเตชั่นส่วนใหญ่และพีซี x86 (i386 หรือใหม่กว่า)
ในบางกรณี (เช่น OS/2, Win32) จะมีการจัดหา makefile แยกต่างหาก; สิ่งเหล่านี้มีไฟล์ docs/platforms/README.* เฉพาะโฮสต์แยกต่างหาก
ไลบรารีแบบไดนามิกได้รับการสนับสนุนอย่างสมบูรณ์ภายใต้ SunOS/Solaris เท่านั้น (และแม้ว่าการสนับสนุนนั้นจะไม่ทำงานใน Sun 3 รุ่นล่าสุด), Linux, FreeBSD, NetBSD, IRIX, HP/UX, Win32 (ไม่ใช่ win32s) และ OSF/1 บน DEC เครื่อง AXP และบางเครื่องอาจมีรายการอยู่ใกล้ด้านบนสุดของ dyn_load.c บนเครื่องอื่นๆ เราขอแนะนำให้คุณทำอย่างใดอย่างหนึ่งต่อไปนี้:
เพิ่มการสนับสนุนไลบรารีแบบไดนามิก (และส่งโค้ดถึงเรา)
ใช้ไลบรารีเวอร์ชันคงที่
จัดเรียงไลบรารีไดนามิกเพื่อใช้ malloc มาตรฐาน สิ่งนี้ยังคงเป็นอันตรายหากห้องสมุดจัดเก็บตัวชี้ไปยังวัตถุที่รวบรวมขยะ แต่อินเทอร์เฟซมาตรฐานเกือบทั้งหมดห้ามสิ่งนี้ เนื่องจากมีการจัดการอย่างถูกต้องกับพอยน์เตอร์เพื่อสแต็กอ็อบเจ็กต์ที่จัดสรร ( strtok
เป็นข้อยกเว้น อย่าใช้มัน)
ในทุกกรณี เราถือว่าการจัดตำแหน่งตัวชี้สอดคล้องกับที่บังคับใช้โดยคอมไพเลอร์ C มาตรฐาน หากคุณใช้คอมไพเลอร์ที่ไม่เป็นมาตรฐาน คุณอาจต้องปรับพารามิเตอร์การจัดตำแหน่งที่กำหนดไว้ใน include/private/gc_priv.h
โปรดทราบว่านี่อาจเป็นปัญหากับเรคคอร์ด/โครงสร้างที่แพ็ก หากสิ่งเหล่านั้นบังคับใช้การจัดตำแหน่งน้อยกว่าสำหรับพอยน์เตอร์
พอร์ตไปยังเครื่องที่ไม่ได้ระบุที่อยู่แบบไบต์หรือไม่ได้ใช้ที่อยู่ 32 บิตหรือ 64 บิตจะต้องใช้ความพยายามอย่างมาก พอร์ตไปยัง MSDOS ธรรมดาหรือ win16 นั้นยาก
สำหรับเครื่องที่ไม่ได้กล่าวถึง หรือสำหรับคอมไพเลอร์ที่ไม่เป็นมาตรฐาน คำแนะนำในการย้ายบางส่วนมีให้ไว้ที่นี่
รูทีนต่อไปนี้มีวัตถุประสงค์เพื่อให้ผู้ใช้เรียกใช้โดยตรง โปรดทราบว่าโดยทั่วไปจำเป็นต้องใช้เพียง GC_malloc
เท่านั้น อาจจำเป็นต้องเรียก GC_clear_roots
และ GC_add_roots
หากตัวรวบรวมต้องติดตามจากตำแหน่งที่ไม่เป็นมาตรฐาน (เช่น จากพื้นที่ข้อมูลไลบรารีไดนามิกบนเครื่องที่ตัวรวบรวมยังไม่เข้าใจ) ในบางเครื่อง อาจเป็นที่พึงปรารถนาที่จะตั้งค่า GC_stackbottom
เป็น การประมาณฐานกองซ้อนที่ดี (ด้านล่าง)
รหัสไคลเอ็นต์อาจรวมถึง gc.h
ซึ่งกำหนดสิ่งต่อไปนี้ทั้งหมด และอื่นๆ อีกมากมาย
GC_malloc(bytes)
- จัดสรรวัตถุตามขนาดที่กำหนด ต่างจาก malloc ตรงที่อ็อบเจ็กต์จะถูกล้างก่อนที่จะส่งคืนให้กับผู้ใช้ GC_malloc
จะเรียกใช้ตัวรวบรวมขยะเมื่อพิจารณาว่าสิ่งนี้เหมาะสม GC_malloc อาจส่งคืน 0 หากไม่สามารถรับพื้นที่เพียงพอจากระบบปฏิบัติการ นี่เป็นผลที่ตามมาที่เป็นไปได้มากที่สุดจากการไม่มีพื้นที่เหลือ ผลที่ตามมาที่เป็นไปได้อื่นๆ คือการเรียกใช้ฟังก์ชันจะล้มเหลวเนื่องจากไม่มีพื้นที่สแต็ก หรือตัวรวบรวมจะล้มเหลวด้วยวิธีอื่นเนื่องจากไม่สามารถรักษาโครงสร้างข้อมูลภายในได้ หรือกระบวนการของระบบที่สำคัญจะล้มเหลวและถอดเครื่องออก ความเป็นไปได้เหล่านี้ส่วนใหญ่ไม่ขึ้นอยู่กับการนำ malloc ไปใช้งาน
GC_malloc_atomic(bytes)
- จัดสรรออบเจ็กต์ในขนาดที่กำหนดซึ่งรับประกันว่าจะไม่มีพอยน์เตอร์ใดๆ ไม่รับประกันว่าวัตถุที่ส่งคืนจะถูกเคลียร์ (สามารถแทนที่ได้ด้วย GC_malloc
เสมอ แต่ส่งผลให้มีเวลาการรวบรวมเร็วขึ้น ตัวรวบรวมอาจจะทำงานเร็วขึ้นหากอาร์เรย์อักขระขนาดใหญ่ ฯลฯ ได้รับการจัดสรรด้วย GC_malloc_atomic
มากกว่าการจัดสรรแบบคงที่)
GC_realloc(object, new_bytes)
- เปลี่ยนขนาดของวัตถุให้เป็นขนาดที่กำหนด ส่งกลับตัวชี้ไปยังวัตถุใหม่ซึ่งอาจหรืออาจจะไม่เหมือนกับตัวชี้ไปยังวัตถุเก่า วัตถุใหม่จะถูกมองว่าเป็นอะตอมก็ต่อเมื่อวัตถุเก่าเป็น ถ้าวัตถุใหม่เป็นแบบรวมและมีขนาดใหญ่กว่าวัตถุต้นฉบับ ไบต์ที่เพิ่มใหม่จะถูกล้าง นี่เป็นโอกาสอย่างมากที่จะจัดสรรออบเจ็กต์ใหม่
GC_free(object)
- จัดสรรคืนวัตถุอย่างชัดเจนโดย GC_malloc
หรือ GC_malloc_atomic
หรือเพื่อน ไม่จำเป็น แต่สามารถใช้เพื่อย่อคอลเลกชันให้เหลือน้อยที่สุดได้หากประสิทธิภาพเป็นสิ่งสำคัญ อาจสูญเสียประสิทธิภาพสำหรับวัตถุขนาดเล็กมาก (<= 8 ไบต์)
GC_expand_hp(bytes)
- เพิ่มขนาดฮีปอย่างชัดเจน (โดยปกติจะทำโดยอัตโนมัติหากการรวบรวมขยะไม่สามารถเรียกคืนหน่วยความจำได้เพียงพอ การเรียก GC_expand_hp
อย่างชัดเจนอาจป้องกันการรวบรวมบ่อยครั้งโดยไม่จำเป็นเมื่อเริ่มต้นโปรแกรม)
GC_malloc_ignore_off_page(bytes)
- เหมือนกับ GC_malloc
แต่ไคลเอนต์สัญญาว่าจะเก็บตัวชี้ไปยังที่ใดที่หนึ่งภายในบล็อกฮีป GC แรก (512 .. 4096 ไบต์หรือมากกว่านั้น ขึ้นอยู่กับการกำหนดค่า) ของออบเจ็กต์ในขณะที่ใช้งานอยู่ (ตัวชี้นี้โดยปกติควรประกาศว่ามีความผันผวนเพื่อป้องกันการรบกวนจากการปรับแต่งคอมไพเลอร์ให้เหมาะสม) นี่เป็นวิธีที่แนะนำในการจัดสรรอะไรก็ตามที่มีแนวโน้มว่ามีขนาดใหญ่กว่า 100 KB หรือมากกว่านั้น ( GC_malloc
อาจส่งผลให้ไม่สามารถเรียกคืนอ็อบเจ็กต์ดังกล่าวได้)
GC_set_warn_proc(proc)
- สามารถใช้เพื่อเปลี่ยนเส้นทางคำเตือนจากตัวรวบรวม คำเตือนดังกล่าวควรเกิดขึ้นไม่บ่อยนัก และไม่ควรละเลยในระหว่างการพัฒนาโค้ด
GC_enable_incremental()
- เปิดใช้งานการรวบรวมรุ่นและส่วนเพิ่ม มีประโยชน์สำหรับฮีปขนาดใหญ่บนเครื่องที่ให้การเข้าถึงข้อมูลสกปรกของเพจ การใช้งานบิตสกปรกบางอย่างอาจรบกวนการดีบัก (โดยการตรวจจับข้อบกพร่องของที่อยู่) และวางข้อจำกัดเกี่ยวกับอาร์กิวเมนต์ฮีปในการเรียกของระบบ (เนื่องจากข้อบกพร่องในการเขียนภายในการเรียกของระบบอาจไม่ได้รับการจัดการอย่างดี)
GC_register_finalizer(object, proc, data, 0, 0)
and friends - อนุญาตให้ลงทะเบียนโค้ดสรุปผล รหัสการสรุปที่ผู้ใช้ระบุ ( (*proc)(object, data)
) ถูกเรียกใช้หลังจากที่อ็อบเจ็กต์ไม่สามารถเข้าถึงได้ สำหรับการใช้งานที่ซับซ้อนยิ่งขึ้น และสำหรับปัญหาการเรียงลำดับขั้นสุดท้าย โปรดดูที่ gc.h
ตัวแปรโกลบอล GC_free_space_divisor
อาจถูกปรับเพิ่มขึ้นจากค่าเริ่มต้นที่ 3 เพื่อใช้พื้นที่น้อยลงและเวลาการรวบรวมมากขึ้น หรือปรับลงเพื่อให้ได้ผลตรงกันข้าม การตั้งค่าเป็น 1 เกือบจะปิดการใช้งานคอลเลกชันและทำให้การจัดสรรทั้งหมดเพิ่มฮีป
ตัวแปร GC_non_gc_bytes
ซึ่งโดยปกติจะเป็น 0 อาจมีการเปลี่ยนแปลงเพื่อให้สะท้อนถึงจำนวนหน่วยความจำที่จัดสรรโดยรูทีนข้างต้น ซึ่งไม่ควรพิจารณาว่าเป็นตัวเลือกสำหรับการรวบรวม การใช้อย่างไม่ระมัดระวังอาจส่งผลให้มีการใช้หน่วยความจำมากเกินไป
การปรับแต่งเพิ่มเติมบางอย่างสามารถทำได้ผ่านพารามิเตอร์ที่กำหนดไว้ใกล้กับด้านบนของ include/private/gc_priv.h
หากตั้งใจจะใช้เพียง GC_malloc
อาจเหมาะสมที่จะกำหนด:
#define malloc(n) GC_malloc(n) #define calloc(m,n) GC_malloc((m)*(n))
สำหรับโค้ดขนาดเล็กที่มีการจัดสรรอย่างเข้มข้น gc_inline.h
จะมีมาโครการจัดสรรบางส่วนที่อาจใช้แทน GC_malloc
และเพื่อน ๆ
ชื่อที่มองเห็นได้จากภายนอกทั้งหมดในตัวรวบรวมขยะเริ่มต้นด้วย GC_
เพื่อหลีกเลี่ยงความขัดแย้งของชื่อ รหัสไคลเอ็นต์ควรหลีกเลี่ยงคำนำหน้านี้ ยกเว้นเมื่อเข้าถึงรูทีนตัวรวบรวมขยะ
มีข้อกำหนดในการจัดสรรพร้อมข้อมูลประเภทที่ชัดเจน สิ่งนี้ไม่ค่อยจำเป็น รายละเอียดสามารถพบได้ใน gc_typed.h
อินเทอร์เฟซ Ellis-Hull C++ ไปยังตัวรวบรวมจะรวมอยู่ในการกระจายตัวรวบรวม หากคุณต้องการใช้สิ่งนี้ ให้พิมพ์ ./configure --enable-cplusplus && make
(หรือ cmake -Denable_cplusplus=ON . && cmake --build .
หรือ make -f Makefile.direct c++
ขึ้นอยู่กับระบบบิลด์ที่คุณใช้) ซึ่งจะสร้างไฟล์ libgccpp.a และ libgctba.a หรือไฟล์ที่เทียบเท่ากับไลบรารีที่แบ่งใช้ (libgccpp.so และ libgctba.so) คุณควรลิงก์กับอันแรก (gccpp) หรืออันที่สอง (gctba) แต่ไม่ใช่ทั้งสองอย่าง ดู gc_cpp.h
และที่นี่ สำหรับคำจำกัดความของอินเทอร์เฟซ อินเทอร์เฟซนี้พยายามประมาณข้อเสนอการรวบรวมขยะ Ellis-Detlefs C++ โดยไม่มีการเปลี่ยนแปลงคอมไพเลอร์
บ่อยครั้งที่จำเป็นต้องใช้ gc_allocator.h
และตัวจัดสรรที่ประกาศไว้ที่นั่นเพื่อสร้างโครงสร้างข้อมูล STL มิฉะนั้นวัตถุย่อยของโครงสร้างข้อมูล STL จะถูกจัดสรรโดยใช้ตัวจัดสรรระบบ และวัตถุที่อ้างอิงถึงอาจถูกรวบรวมก่อนเวลาอันควร
ตัวรวบรวมอาจถูกใช้เพื่อติดตามรอยรั่วในโปรแกรม C ที่ตั้งใจให้ทำงานด้วย malloc/ฟรี (เช่น โค้ดที่มีข้อจำกัดแบบเรียลไทม์หรือความสามารถในการพกพาที่รุนแรง) หากต้องการทำเช่นนั้น ให้กำหนด FIND_LEAK
ใน Makefile สิ่งนี้จะทำให้ตัวรวบรวมพิมพ์คำอธิบายอ็อบเจ็กต์ที่มนุษย์สามารถอ่านได้ทุกครั้งที่พบอ็อบเจ็กต์ที่ไม่สามารถเข้าถึงได้และไม่ได้รับการปลดปล่อยอย่างชัดเจน วัตถุดังกล่าวจะถูกเรียกคืนโดยอัตโนมัติเช่นกัน
หากออบเจ็กต์ทั้งหมดได้รับการจัดสรรด้วย GC_DEBUG_MALLOC
(ดูหัวข้อถัดไป) ตามค่าเริ่มต้น คำอธิบายออบเจ็กต์ที่มนุษย์สามารถอ่านได้อย่างน้อยจะมีไฟล์ต้นฉบับและหมายเลขบรรทัดที่มีการจัดสรรออบเจ็กต์ที่รั่วไหลออกมา บางครั้งอาจเพียงพอแล้ว (ในเครื่องบางเครื่อง มันจะรายงานการติดตามสแต็กที่เป็นความลับด้วย หากนี่ไม่ใช่เชิงสัญลักษณ์ บางครั้งก็สามารถเรียกเข้าสู่การติดตามสแต็กสัญลักษณ์ได้โดยการเรียกใช้โปรแกรม "foo" ด้วย tools/callprocs.sh foo
มันเป็นเชลล์แบบสั้น สคริปต์ที่เรียกใช้ adb เพื่อขยายค่าตัวนับโปรแกรมไปยังที่อยู่เชิงสัญลักษณ์ ส่วนใหญ่จัดทำโดย Scott Schwartz)
โปรดทราบว่าเครื่องมือในการแก้ไขจุดบกพร่องที่อธิบายไว้ในส่วนถัดไปบางครั้งอาจมีประสิทธิภาพน้อยลงเล็กน้อยในโหมดค้นหารอยรั่ว เนื่องจากในรุ่นหลัง GC_debug_free
ส่งผลให้มีการใช้ออบเจ็กต์ซ้ำจริงๆ (ไม่เช่นนั้นวัตถุจะถูกทำเครื่องหมายว่าไม่ถูกต้อง) นอกจากนี้ โปรดทราบว่าการทดสอบ GC ส่วนใหญ่ไม่ได้ออกแบบมาให้ทำงานอย่างมีความหมายในโหมด FIND_LEAK
รูทีน GC_debug_malloc
, GC_debug_malloc_atomic
, GC_debug_realloc
และ GC_debug_free
จัดเตรียมอินเทอร์เฟซสำรองให้กับตัวรวบรวม ซึ่งให้ความช่วยเหลือเกี่ยวกับข้อผิดพลาดในการเขียนทับหน่วยความจำ และอื่นๆ ที่คล้ายกัน ออบเจ็กต์ที่จัดสรรในลักษณะนี้จะมีคำอธิบายประกอบพร้อมข้อมูลเพิ่มเติม ข้อมูลบางส่วนนี้ได้รับการตรวจสอบในระหว่างการรวบรวมขยะ และความไม่สอดคล้องกันที่ตรวจพบจะถูกรายงานไปยัง stderr
กรณีง่ายๆ ของการเขียนที่เลยจุดสิ้นสุดของอ็อบเจ็กต์ที่จัดสรรควรถูกจับได้ หากอ็อบเจ็กต์ถูกจัดสรรคืนอย่างชัดเจน หรือหากตัวรวบรวมถูกเรียกใช้ในขณะที่อ็อบเจ็กต์นั้นใช้งานอยู่ การจัดสรรคืนครั้งแรกของออบเจ็กต์จะล้างข้อมูลการดีบักที่เกี่ยวข้องกับออบเจ็กต์ ดังนั้นการเรียก GC_debug_free
ซ้ำๆ โดยไม่ตั้งใจจะรายงานการจัดสรรคืนของออบเจ็กต์โดยไม่มีข้อมูลการดีบั๊ก ข้อผิดพลาดหน่วยความจำไม่เพียงพอจะถูกรายงานไปยัง stderr นอกเหนือจากการส่งคืน NULL
การตรวจสอบ GC_debug_malloc
ระหว่างการรวบรวมขยะถูกเปิดใช้งานด้วยการเรียกฟังก์ชันนี้ครั้งแรก ซึ่งจะส่งผลให้มีการชะลอตัวระหว่างการรวบรวม หากต้องการตรวจสอบฮีปบ่อยๆ สามารถทำได้โดยการเรียกใช้ GC_gcollect
อย่างชัดเจน เช่น จากดีบักเกอร์
ไม่ควรส่งอ็อบเจ็กต์ที่จัดสรร GC_debug_malloc
ไปยัง GC_realloc
หรือ GC_free
และในทางกลับกัน อย่างไรก็ตาม เป็นที่ยอมรับได้ในการจัดสรรเฉพาะบางอ็อบเจ็กต์ด้วย GC_debug_malloc
และใช้ GC_malloc
สำหรับอ็อบเจ็กต์อื่น โดยที่ทั้งสองพูลจะถูกเก็บไว้แยกกัน ในกรณีนี้ มีความเป็นไปได้ต่ำมากที่วัตถุที่จัดสรร GC_malloc
อาจถูกระบุผิดว่าถูกเขียนทับแล้ว สิ่งนี้ควรเกิดขึ้นด้วยความน่าจะเป็นมากที่สุดหนึ่งใน 2**32 ความน่าจะเป็นนี้เป็นศูนย์หากไม่เคยถูกเรียก GC_debug_malloc
GC_debug_malloc
, GC_debug_malloc_atomic
และ GC_debug_realloc
รับอาร์กิวเมนต์ต่อท้ายเพิ่มเติมอีกสองตัว ได้แก่ สตริงและจำนวนเต็ม สิ่งเหล่านี้ไม่ได้ถูกตีความโดยผู้จัดสรร พวกมันจะถูกเก็บไว้ในออบเจ็กต์ (สตริงจะไม่ถูกคัดลอก) หากตรวจพบข้อผิดพลาดเกี่ยวกับวัตถุ ข้อผิดพลาดเหล่านั้นจะถูกพิมพ์ออกมา
แมโคร GC_MALLOC
, GC_MALLOC_ATOMIC
, GC_REALLOC
, GC_FREE
, GC_REGISTER_FINALIZER
และเพื่อนก็มีให้เช่นกัน สิ่งเหล่านี้ต้องการอาร์กิวเมนต์เดียวกันกับรูทีนที่สอดคล้องกัน (ไม่มีการดีบั๊ก) หากรวม gc.h
ไว้กับ GC_DEBUG
ที่กำหนดไว้ จะมีการเรียกเวอร์ชันการดีบักของฟังก์ชันเหล่านี้ โดยส่งชื่อไฟล์ปัจจุบันและหมายเลขบรรทัดเป็นอาร์กิวเมนต์เพิ่มเติมสองตัวตามความเหมาะสม หากรวม gc.h
ไว้โดยไม่ได้กำหนด GC_DEBUG
มาโครเหล่านี้ทั้งหมดจะถูกกำหนดให้เทียบเท่ากับการไม่แก้ไขจุดบกพร่องแทน ( GC_REGISTER_FINALIZER
เป็นสิ่งจำเป็น เนื่องจากตัวชี้ไปยังออบเจ็กต์ที่มีข้อมูลการดีบักจริงๆ แล้วเป็นตัวชี้ไปยังการแทนที่ 16 ไบต์จากจุดเริ่มต้นของออบเจ็กต์ และการแปลบางอย่างจำเป็นเมื่อมีการเรียกใช้รูทีนการสรุปผล สำหรับรายละเอียดเกี่ยวกับสิ่งที่เก็บไว้ในส่วนหัว โปรดดูคำจำกัดความ ประเภท oh ในไฟล์ dbg_mlc.c)
โดยปกติตัวรวบรวมจะขัดจังหวะโค้ดไคลเอ็นต์ในช่วงระยะเวลาของเฟสการทำเครื่องหมายการรวบรวมขยะ สิ่งนี้อาจยอมรับไม่ได้หากจำเป็นต้องมีการตอบสนองแบบโต้ตอบสำหรับโปรแกรมที่มีฮีปขนาดใหญ่ ตัวรวบรวมยังสามารถทำงานในโหมด "รุ่น" ซึ่งโดยปกติแล้วจะพยายามรวบรวมเฉพาะอ็อบเจ็กต์ที่จัดสรรตั้งแต่การรวบรวมขยะครั้งล่าสุด นอกจากนี้ ในโหมดนี้ การรวบรวมขยะจะทำงานแบบค่อยเป็นค่อยไปเป็นส่วนใหญ่ โดยมีงานจำนวนเล็กน้อยที่ดำเนินการเพื่อตอบสนองคำขอ GC_malloc
จำนวนมากแต่ละรายการ
โหมดนี้เปิดใช้งานได้โดยการเรียก GC_enable_incremental
การรวบรวมแบบเพิ่มหน่วยและแบบเจนเนอเรชันจะมีประสิทธิภาพในการลดเวลาหยุดชั่วคราวก็ต่อเมื่อตัวรวบรวมมีวิธีบางอย่างที่จะบอกว่าอ็อบเจ็กต์หรือเพจใดที่ได้รับการแก้ไขเมื่อเร็ว ๆ นี้ ผู้รวบรวมใช้แหล่งข้อมูลสองแหล่ง:
ข้อมูลที่จัดทำโดยระบบ VM ซึ่งอาจระบุไว้ในรูปแบบใดรูปแบบหนึ่ง ภายใต้ Solaris 2.X (และอาจอยู่ภายใต้ระบบอื่นที่คล้ายคลึงกัน) ข้อมูลบนเพจสกปรกสามารถอ่านได้จากระบบไฟล์ /proc ภายใต้ระบบอื่นๆ (เช่น SunOS4.X) เป็นไปได้ที่จะป้องกันการเขียนฮีป และตรวจจับข้อผิดพลาดที่เกิดขึ้น บนระบบเหล่านี้ เราต้องการให้การเรียกของระบบเขียนไปยังฮีป (นอกเหนือจากการอ่าน) ได้รับการจัดการเป็นพิเศษด้วยโค้ดไคลเอ็นต์ ดู os_dep.c
สำหรับรายละเอียด
ข้อมูลที่จัดทำโดยโปรแกรมเมอร์ วัตถุถือว่าสกปรกหลังจากการเรียก GC_end_stubborn_change
โดยมีเงื่อนไขว่าไลบรารีได้รับการคอมไพล์อย่างเหมาะสม โดยทั่วไปแล้วมันไม่คุ้มที่จะใช้กับวัตถุอายุสั้น โปรดทราบว่าข้อบกพร่องที่เกิดจากการเรียก GC_end_stubborn_change
หรือ GC_reachable_here
ที่หายไปนั้นมีแนวโน้มที่จะพบไม่บ่อยนักและติดตามได้ยาก
หน่วยความจำใดๆ ที่ไม่มีตัวชี้ที่จดจำได้จะถูกเรียกคืน ลิงก์ไปข้างหน้าและข้างหลังในรายการแบบเอกสิทธิ์เฉพาะบุคคลไม่ได้ตัดทอน
เครื่องมือเพิ่มประสิทธิภาพ C บางตัวอาจสูญเสียตัวชี้ที่ไม่เปิดเผยตัวสุดท้ายไปยังออบเจ็กต์หน่วยความจำอันเป็นผลมาจากการปรับให้เหมาะสมที่ชาญฉลาด สิ่งนี้แทบไม่เคยมีใครสังเกตเห็นในทางปฏิบัติเลย
นี่ไม่ใช่ตัวสะสมตามเวลาจริง ในการกำหนดค่ามาตรฐาน เปอร์เซ็นต์ของเวลาที่ต้องใช้ในการรวบรวมควรคงที่ตามขนาดฮีป แต่การหยุดคอลเลกชันจะเพิ่มขึ้นสำหรับฮีปที่ใหญ่ขึ้น พวกมันจะลดลงตามจำนวนโปรเซสเซอร์หากเปิดใช้งานการทำเครื่องหมายแบบขนาน
(ในเครื่องวินเทจปี 2007 เวลา GC อาจอยู่ในลำดับ 5 มิลลิวินาทีต่อ MB ของหน่วยความจำที่เข้าถึงได้ซึ่งจำเป็นต้องสแกนและประมวลผล ระยะทางของคุณอาจแตกต่างกันไป) สิ่งอำนวยความสะดวกในการรวบรวมแบบเพิ่ม/สร้างอาจช่วยได้ในบางกรณี
โปรดระบุรายงานข้อบกพร่องและแนวคิดเกี่ยวกับคุณลักษณะใหม่ๆ สำหรับปัญหา GitHub ก่อนส่งโปรดตรวจสอบว่ายังไม่ได้ดำเนินการโดยบุคคลอื่น
หากคุณต้องการมีส่วนร่วม ให้ส่งคำขอดึงไปที่ GitHub โปรดประมวลผลไฟล์ที่แก้ไขด้วยรูปแบบเสียงดังกราวก่อนส่ง
หากคุณต้องการความช่วยเหลือ ให้ใช้ Stack Overflow การอภิปรายทางเทคนิคเก่าๆ มีอยู่ในไฟล์เก็บถาวรรายชื่อผู้รับเมล bdwgc
ซึ่งสามารถดาวน์โหลดเป็นไฟล์บีบอัดหรือเรียกดูได้ที่ Narkive
หากต้องการรับประกาศเปิดตัวใหม่ ให้สมัครรับฟีด RSS (หากต้องการรับการแจ้งเตือนทางอีเมล คุณสามารถตั้งค่าบริการฟรีของบุคคลที่สาม เช่น IFTTT RSS Feed ได้) หากต้องการรับการแจ้งเตือนในทุกประเด็น โปรดดูโปรเจ็กต์บน GitHub
ความตั้งใจของเราคือการทำให้ bdwgc (libgc) ใช้งานง่ายทั้งในซอฟต์แวร์ฟรีและเป็นกรรมสิทธิ์ ดังนั้นโค้ดตัวรวบรวมขยะแบบอนุรักษ์นิยมของ Boehm-Demers-Weiser ที่เราคาดว่าจะเชื่อมโยงแบบไดนามิกหรือแบบคงที่ในแอปพลิเคชันไคลเอนต์จึงได้รับการคุ้มครองโดยใบอนุญาตของตัวเอง ซึ่งมีลักษณะคล้ายกับรูปแบบ MIT
ข้อมูลใบอนุญาตที่แน่นอนมีอยู่ในไฟล์ LICENSE
ผู้ร่วมให้ข้อมูลทั้งหมดแสดงอยู่ในไฟล์ AUTHORS