Mechanism to detect and reclaim leaks ARC cannot handle alone

Originator:jeremytregunna
Number:rdar://14019336 Date Originated:29-May-2013 07:39 PM
Status:Open Resolved:No
Product:Developer Tools Product Version:N/A
Classification:Feature (New) Reproducible:N/A
 
Summary:
Under ARC, when accessing an instance variable within a block, it is entirely possible to create a retain cycle when the block captures self that ARC is unable to reclaim. This leaves the programmer to manually spot this, and take a weak reference to one of the objects in the cycle, so that ARC is able to reclaim the objects. This enhancement suggestion proposes two methods for this problem to be easier for developers to handle.

General Method:
Both methods require a base to build on. This base includes a precise concurrent garbage collector. For the sake of argument, let us assume a simple mark-sweep collector augmented with a lightweight concurrent algorithm I'll describe below:
1. When creating the GC instance, create a separate queue or thread for the "recycler". A recycler is defined as being the program which scans over the known roots and reclaims memory according to these rules.
2. Main a cycle count, initially set to 0.
3. When allocating objects, set their cycle number to the value of the current cycle counter created in step 2
4. After a collection cycle occurs, atomically increment this cycle count using a fetch-and-add instruction.
5. When the recycler scans the roots, it looks for objects whose cycle number is 2 less than the current collection cycle count, and scans those objects for strong references, according to the basic rules of a mark-sweep collector.
6. Any surviving objects have their cycle count incremented by one using an atomic fetch-and-add instruction.
7. All remaining garbage will be zeroed so that ARC may reclaim the resources at that time.

This simple concurrent algorithm is outlined in detail in [1]

Of course, it is only one possible concurrent algorithm.

Method 1: Manual Promotion
By way of some API, I as a programmer expect to be able to promote an object that I believe might leak, to henceforth be maintained by the recycler.
This is just as error prone as taking a weak reference to an object explicitly and remembering to break the reference when you're done. It is not a method I recommend, but at least better than taking a weak ref and remembering to break the cycle later, all we would have to do in this method is when we introduce the object, tell the recycler about it and then not worry about it going forward. One place in the code does help make this slightly less error prone.

Method 2: Automatic Scanning
For any object that the compiler reasonably believes to be involved in a cycle, as these processes get better over time, can instead insert a call to automatically promote objects it believes are involved in cycles. This doesn't solve the whole problem, but as static analysis tools become better over time, this method will catch more objects.

Both of these methods have one benefit: By and large, many of the objects will not be involved with the recycler at any given time, and therefore not be subject to much of the cost of traditional garbage collection. Also, since we only work with objects, whose layout we know ahead of time, we can be precise about our scanning, as opposed to being conservative. The one caveat here is blocks would need to be given an unlimited extent whenever they're found during a scan or promotion operation. This is one possible area of contention.

References:
[1] "Very Concurrent Mark and Sweep Garbage Collection without Fine-Grain Synchronization" available for free at http://doc.cat-v.org/inferno/concurrent_gc/concurrent_gc.pdf

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!