220 likes | 484 Views
Garbage Collection in the Next C++ Standard. Hans-J. Boehm, Mike Spertus, Symantec. The Context (1). Conservative garbage collection for C and C++ has been used for 20+ years. Usually works, possibly with a small amount of tweaking. Especially for 64-bit applications.
E N D
Garbage Collection in the Next C++ Standard Hans-J. Boehm, Mike Spertus, Symantec
The Context (1) • Conservative garbage collection for C and C++ has been used for 20+ years. • Usually works, possibly with a small amount of tweaking. • Especially for 64-bit applications. • More attractive with multi-core processors. • Explicit memory management gets harder with threads. • Some parallel programming techniques much more difficult/expensive without GC. • GC parallelizes better than malloc/free. • GC-based leak detectors are also common. • One major limiting factor: • C and C++ standards don’t fully sanction garbage collecting implementations. • Programmers are hesitant to use nonstandard tools.
The Context (2) • C++ standard is undergoing revision. • “C++0x” expected somewhere near 2010 or 2011. • Initial committee draft was put out for review. • Many other new features: • “Concepts” (Templates type-checked in isolation). • Threads support (threads API, memory model, atomics). • struggling with object lifetime issues. • Library-based classic reference counting (shared_ptr). • R-value references (references to otherwise inaccessible values) support low-cost shared_ptr moves. • Microsoft’s C++/CLI provides a separate garbage-collected heap.
Our Goal • “Transparent” garbage collection. • Ordinary pointers; works with existing library code. • Supports • Code designed for GC • Leak detection • “Litter collection” • Supports atomic pointers with cheap assignment.
Our Proposal, version 1 • GC support in the implementation “mandatory”. • GC use optional, but must be consistent across application. • If you have to trace a section of the heap, you might as well collect it. • Program sections specify “gc_forbidden”, “gc_required”, or “gc_safe” (default). • Linker diagnoses conflicts. • Annotations can specify when integral types may contain pointers. • This proposal is currently on hold, not in CD.
Issues with original proposal (1) • gc_required / gc_forbiddenmust be consistent for whole program: • Too coarse. • Need to deal with plug-ins with limited interface.
Issues with original proposal (2) class C { int indx; // E[indx] contains // associated data. // Finalizer cleans up E[indx] void foo() { int i = indx; // this dead here. // May be finalized? bar(E[i]); } • Finalization is needed for interaction of GC with explicit resource management. • Finalization is problematic in the presence of dead variable elimination.
Our proposal, version 2 • Minimal compromise proposal • Garbage collected implementations are allowed, not required. • Officially allows collection of memory allocated with built-in operator new. • malloc() is arguably in the domain of the C committee. • malloc() garbage collection may be harder to retrofit. • Not intended as long term replacement for proposal 1. • In current Committee Draft.
Proposal 2 components • Allow unreachable objects to be reclaimed. • Provide a simple API to • Explicitly prevent reclamation of specified objects (declare_reachable()). • Declare that certain objects do not need to be traced because they contain no pointers (declare_no_pointers()).
Reclamation of unreachable objects in C++ • Existing conservative collectors reclaim objects not reachable via pointer chains from variables. • Leak detectors make similar assumptions. • But current standard does not guarantee that unreachable objects are dead. • Disallow this! • Unavoidably a compatibility issue intptr_t q = ~(intptr_t)p; p = 0; … p = (foo *)(~q); … *p …
This isn’t as easy as it looks … • Initial attempt: • Objects that were once unreachable may not be dereferenced (incl. deallocation). • Insufficient: int_ptr_t q = ~(intptr_t)p; … foo *r = (foo *)(~q); p = 0; … *r …
A better formulation • Only safely-derived pointers may be dereferenced. • A safely-derived pointer was computed without intervening integer arithmetic from another safely-derived pointer. • Safely-derived pointers may only be stored in • pointer objects. • integer objects of sufficient size. • aligned character arrays. • Whether a value is safely derived depends on how it was computed, not on the bits representing the pointer. • Sometimes p safely derived, r not, but p == r. • Draft standard contains a precise inductive definition. Thanks to Clark Nelson (Intel).
API addition 1 • Declare_reachable() / undeclare_reachable() allow a pointer to be dereferenced even if it is not safely-derived. • No-ops in non-GC implementation. • Allow old code to be retrofitted. • Undeclare_reachable() returns safely derived copy of pointer.
Declare_reachable() example declare_reachable(p); int_ptr_t q = ~(intptr_t)p; p = 0; … p = undeclare_reachable(foo *)(~q); … *p …
Implementation Challenges • Implemented as global GC-visible multiset representation, but: • Declare_reachable() applies to complete objects. Undeclare_reachable() argument need not match exactly. • Matching calls don’t need to come from the same thread: Scalability with thread/processor count.
API Addition 2 • Declare_no_pointers(p,n) / undeclare_no_pointers(p,n) declares the address range [p, p+n) to not hold pointers; safely derived pointers may not be stored there. • Allows the programmer to specify more “type” information. • Much more compatible with C++ constructor/destructor model than allocation-time specifications. • Can be applied to static/stack/heap objects. • Undeclare_no_pointers() must be called before explicit deallocation.
Declare_no_pointers () example class foo { foo * next; char cmprsd[N]; public: foo() { … declare_no_pointers(cmprsd, N); } ~foo() { … undeclare_no_pointers(cmprsd, N); } … }
Implementation Challenges • Efficient handling for frequently constructed stack objects. • Scalability.
Prototype Implementation • Currently just track registered ranges. • Processing deferred to GC time. • Keep a small number of ranges in a thread-local data structure. • Very small ranges and smaller objects are currently ignored.
Preliminary Performance Measurements processor nsecs/op-pair threads
Conclusions • Current C++0x draft explicitly allows garbage-collected implementations. • Support APIs differ from existing implementations. • For good reasons, we think. • New set of implementation challenges. • More extensive GC support will be considered after C++0x. • Not too late for comments.