GCKit ===== GCKit is a garbage collection kit designed for Objective-C. It is a hybrid collector, using a combination of reference counting, cycle detection, and tracing. The design goals are: - Easy interoperability with non-GC code using retain/release semantics. - Easy interoperability with code designed for Apple's GC implementation. - Support for assisted reference counting with no compiler support. - Support for automatic garbage collection with compiler support. - Low overheads. - Performance in memory-constrained conditions, without causing undue swapping Memory Types ------------ There are three types of memory in GCKit's model: - Objects - Traced regions - Untraced regions Objects have a fixed layout and may contain strong, weak, and traced pointers. Traced regions include the stack, and any regions explicitly designated for tracing. Stacks are traced synchronously, from the thread that owns them, while other regions are not. Untraced regions are opaque to GCKit. They may contain pointers to GC'd objects only if the pointers are manually reference counted using GCRetain() and GCRelease(). Object Types ------------ GCKit will allocate two kind of memory. Objective-C objects, and buffers. Reference Types --------------- There are four kinds of reference (pointer) in GCKit's memory model: - Strong. - Zeroing weak. - Traced. - Invisible. Strong references use reference counting. When an object is strongly assigned to a pointer, its reference count is incremented and the reference count of the old object is decremented. Objects will never be deleted as long as they have a strong reference count greater than 0 and their references can not all be accounted for by cycles. Zeroing weak references are also reference counted, however they do not prevent an object from being finalized. Zeroing weak references follow similar assignment semantics to strong references. When an object is only referenced by zeroing weak references, it will be finalized, but not freed. Subsequent reads of zeroing weak pointers to the object will decrement its reference count and it will be freed once this reaches 0. Traced pointers do not perform any reference counting. All pointers on the stack are traced, as are pointers in memory buffers explicitly allocated for tracing. Objects with a reference count of 0 will not be freed until tracing these regions determines that there are no unseen references to them. Copying traced pointers between stacks directly is not supported. If a thread somehow gets a reference to another thread's stack and copies a pointer then the compiler will not generate a write barrier. This means that, if the two threads' stacks are not traced in the right order relative to each other (50% chance) and there are no locatable heap references to the object then it may be freed. Invisible pointers are outside regions that the garbage collector knows about. Objects pointed to by these may be deleted if their reference count hits 0. Interior pointers are not supported. A pointer to the start of an object or managed buffer must be maintained Object Deletion --------------- Objects marked as using CoreFoundation semantics are deleted as soon as their reference counts hit 0. All other objects are marked as potential garbage once their reference count drops to a value that is equal to the number of references that the cycle detector can find. If A and B both hold strong references to each other, then they are marked as potential garbage once their reference count hits 1. Interfaces ---------- Writing pointers into traced heap memory requires a write barrier. The objc_assign_strongCast function generates this barrier for a single write (another function, as yet unwritten, will generate it for multiple writes). Assignments to instance variables or globals must increment the strong reference count of the new value and decrement the value of the old one. The objc_assignIvar() and objc_assignGlobal() functions perform this for you. If you are storing pointers in memory that is not managed by GCKit then you must call the CGRetain() function on the pointer to prevent it from being freed and the GCRelease() function when you are finished with it. Degenerate Cases ---------------- Objects using the Core Foundation or OpenStep models may set a flag indicating that they do not contain cycles (or, more accurately, that the programmer takes responsibility for freeing cycles). In this case, GCKit will trace the stack, catching bugs where you might have used -release instead of -autorelease, but aside from that will not provide any benefits. Objects may also be marked as having CF semantics. In this case, they will be checked for cycles (unless explicitly marked as acyclic), but will be finalised when their reference count hits zero and subsequently destroyed when their weak reference count hits zero. Finally, you can use traced memory for everything. Don't do this. GCKit is designed to be efficient when only a relatively small proportion of allocated memory needs to be traced. Outstanding Bugs ---------------- Lots. Seriously, don't use GCKit yet. Cycles in traced memory are not yet detected. Lots of GCKit is completely untested.