Upload
others
View
0
Download
0
Embed Size (px)
Citation preview
iGC Garbage Collection
User’s Manual
Harnix Technologies Inc.
2011-08-16
- 2 -
- 3 -
Contents
Overview ................................................................................................................................................................................................. 6 Basic Concepts ................................................................................................................................................................................ 6
Architecture ............................................................................................................................................................................ 7 How the Garbage Collector Works ............................................................................................................................................ 7 Enabling Garbage Collection .................................................................................................................................................... 8
Features & Specs ............................................................................................................................................................................. 9 Performance Testing ...................................................................................................................................................................... 11
GCBench testing ................................................................................................................................................................... 11 Pause-less testing ................................................................................................................................................................. 11 GC Throughputs.................................................................................................................................................................... 12
FAQs............................................................................................................................................................................................. 12 Programming Guide................................................................................................................................................................................ 14
Object References.......................................................................................................................................................................... 14 Managed reference ............................................................................................................................................................... 14 Strong reference ................................................................................................................................................................... 15 Weak reference..................................................................................................................................................................... 15 Zeroing weak reference ......................................................................................................................................................... 15 Summary.............................................................................................................................................................................. 16 ARCGC_C & Reference Mapping ............................................................................................................................................. 16
Object Reclamation........................................................................................................................................................................ 19 The cleanup routine .............................................................................................................................................................. 19 Immediate reclamation.......................................................................................................................................................... 19 Reclamation ordering ............................................................................................................................................................ 20 Resurrection ......................................................................................................................................................................... 20 Dynamic associated destructor............................................................................................................................................... 21 Reclaim circular depended cycles ........................................................................................................................................... 21
Linear Pool .................................................................................................................................................................................... 21 Features & tech specs ........................................................................................................................................................... 21 Create a linear pool ............................................................................................................................................................... 22 Create an object from a pool ................................................................................................................................................. 22 Drop references to pool or objects ......................................................................................................................................... 22 Evacuate objects from a pool ................................................................................................................................................. 23
API References....................................................................................................................................................................................... 24 Predefined Macros.................................................................................................................................................................................. 25
__OBJC_GC__ .................................................................................................................................................................................. 25 __has_feature(objc_arc) .............................................................................................................................................................. 25 __has_feature(objc_arc_gc) ......................................................................................................................................................... 25 __has_feature(objc_arc_gc_compatible)....................................................................................................................................... 25 __has_feature(objc_hnxgc)........................................................................................................................................................... 25 __has_feature(objc_hnx) .............................................................................................................................................................. 25
Objective-C Methods............................................................................................................................................................................... 26
- 4 -
destruct ....................................................................................................................................................................................... 26 Declaration: .......................................................................................................................................................................... 26 Example:.............................................................................................................................................................................. 26
createFromPool ............................................................................................................................................................................. 26 Declaration: .......................................................................................................................................................................... 26 Example:.............................................................................................................................................................................. 26
__weak .......................................................................................................................................................................................... 27 __autoweak.................................................................................................................................................................................... 27
C Functions ............................................................................................................................................................................................ 28 _hnxgc_collect ............................................................................................................................................................................. 28
Declaration: .......................................................................................................................................................................... 28 _hnxgc_destruct_object................................................................................................................................................................ 28
Declaration: .......................................................................................................................................................................... 28 _hnxgc_add_memory_pressure ......................................................................................................................................................... 28
Declaration: .......................................................................................................................................................................... 28 Example:.............................................................................................................................................................................. 28
_hnxgc_did_receive_memory_warning ............................................................................................................................................. 29 Declaration: .......................................................................................................................................................................... 29 Example:.............................................................................................................................................................................. 29
_hnxgc_set_trace_level................................................................................................................................................................ 29 Declaration: .......................................................................................................................................................................... 29 Example:.............................................................................................................................................................................. 29
_hnxgc_set_cycle_breaker ............................................................................................................................................................ 29 Declaration: .......................................................................................................................................................................... 29
_hnxgc_set_nonrc.......................................................................................................................................................................... 29 Declaration: .......................................................................................................................................................................... 30
_hnxgc_weakref_allocate .............................................................................................................................................................. 30 Declaration: .......................................................................................................................................................................... 30
_hnxgc_weakref_deallocate........................................................................................................................................................... 30 Declaration: .......................................................................................................................................................................... 30
_hnxgc_weakref_read..................................................................................................................................................................... 30 Declaration: .......................................................................................................................................................................... 30
_hnxgc_weakref_write ................................................................................................................................................................... 30 Declaration: .......................................................................................................................................................................... 30
<General C API> ........................................................................................................................................................................... 30 C++ API ................................................................................................................................................................................................ 31
gcptr<T>::i .................................................................................................................................................................................. 31 Declaration: .......................................................................................................................................................................... 31 Example:.............................................................................................................................................................................. 31
gcptr<T> ....................................................................................................................................................................................... 31 Declaration: .......................................................................................................................................................................... 31
gcnew_i......................................................................................................................................................................................... 31 Declaration: .......................................................................................................................................................................... 31
- 5 -
Example:.............................................................................................................................................................................. 31 gcdelete ....................................................................................................................................................................................... 31
Example:.............................................................................................................................................................................. 31 Example 2: ........................................................................................................................................................................... 32
<General C++ API> ...................................................................................................................................................................... 32 Articles .................................................................................................................................................................................................. 33
Maintaining existing RC cleanup ordering ........................................................................................................................................ 34 The problem ......................................................................................................................................................................... 34 Discarded attempts ............................................................................................................................................................... 34 iGC solution .......................................................................................................................................................................... 34
Solving stack overflow due to deep-nested destructions ................................................................................................................... 35 Choosing new style coding ............................................................................................................................................................. 37
Reducing your code writing workload ..................................................................................................................................... 37 Making more cycles non-sensitive to cleanup ordering............................................................................................................. 37 Writing one code for both GC and RC ..................................................................................................................................... 38 Conclusion............................................................................................................................................................................ 38
Advanced Subtle Topics.................................................................................................................................................................. 39 Access after destruction......................................................................................................................................................... 39 Reference counting ............................................................................................................................................................... 39 Aggressive garbage collection ................................................................................................................................................ 39 C++ Exceptions .................................................................................................................................................................... 39 Where GC runs ..................................................................................................................................................................... 39
- 6 -
Overview
iGC is an innovative runtime garbage collector designed for the iOS (iPhoneOS) platform to collect unused objects, including those
circular-referenced, which cannot be reclaimed by Apple's Automatic Reference Counting (ARC) or manual retain/release (MRR) code.
Unlike some other garbage collectors, e.g. the conservative GC in Mac OS X, iGC is fully compatible with reference counting. There is no need to
work with two separate system libraries and frameworks for non-GC and GC apps. Just by linking in your code with the iGC static library, you can
use Objective-C and C++ language to write your auto-managed iOS App with existing system libraries and frameworks from Apple and other 3rd
parties. Only your code knows GC was enabled, while others continue to see your code running as manually managed.
Basically, iGC can be viewed as a combination of reference counting and tracing garbage collection, with the strengths of each merged in a
unique and innovative way that retains the merits and reduces costs. The following illustrate some of its main advantages:
(1) iGC employs a deterministic reclamation of objects (when the last effective reference to the object goes away), where traditional GCs free an
object “sometime later”. This meets programmers’ natural expectations concerning object lifetimes, and makes debugging easier as subtle
memory bugs come out earlier and are reproducible.
(2) The amount of memory required by an iGC app is generally much lower than a traditional GC because objects are released sooner.
(3) Reference counting in iGC helps the system to determine roots for live object traversal. It reduces iGC cost to less than RC + GC.
(4) iGC is accurate. It doesn’t suffer from fraudulent roots because it doesn’t scan stack to determine roots.
(5) iGC never kicks in and suspends your threads. This fully-concurrent GC maintains high responsiveness of UI apps.
(6) Objects are auto-managed by the system. This makes it open to numerous performance optimizations. We can rely on GC to recycle memory
space while maintaining objects being destructed immediately after use. And, the system can move some objects around in heap to provide fast
linear memory allocation, increasing performance by 4x – 6x faster over the standard Objective-C/C++ allocator.
(7) Garbage collection in iGC maintains the same RC reclamation ordering, even when they are referenced by cycles. This feature is important in
order to reuse the existing iOS frameworks and libraries.
Basic Concepts
The iGC system automatically manages your object’s lifetime by monitoring every assignment to ivars, the fields of instance of Objective-C class.
Contributions to reference count from ivars are done automatically by the system. There is no need to explicitly send retain/release messages for
ivars in your iGC program. If you use iOS 5 LLVM Clang 3.0 compiler with ARC enabled, you can use iGC without any retain/release calls.
- 7 -
Let’s take a look at an example of iGC (with ARC enabled).
@interface Node : NSObject { Node *next; } @end @implementation Node + (void)work { Node * pA = [Node alloc]; // create obj `A’ pA->next = [Node alloc]; // create obj `B’ Node * pC = [Node alloc]; // create obj `C’ pC->next = pC; // form a cycle } @end
In the "work" method, when assigning an object reference to ivar `next’, the system will monitor the operation and retain the object, e.g. object
‘B’ is retained by ivar ‘next’, and will be released immediately when object ‘A’ is destructed. Circular referenced objects, like object `C’, will be
eventually collected by garbage collection. There is no memory leak.
Architecture iGC garbage collector is implemented as a static library (libiGC.a). When creating an instance of a class that uses default system [NSObject alloc]
method, the system will automatically invoke iGC API to return a managed object. C++ malloc or other objects created from custom routes are
unmanaged. The system monitors ivar assignments and performs different operations according to whether the type of object is managed or
not.
The collector only scans managed heap. It doesn’t scan traditional root-set areas of other GCs, such as stack, global variables, malloc heap, etc.
Objects created outside managed heap are not affected by the collector.
How the Garbage Collector Works We noticed that cyclic references are only formed within managed heap. Although there are references from root-set, like stacks, to managed
objects, but there is no effective reference from managed heap to the outside. From the collector’s point of view, the reference graph between
outside and heap is acyclic. It is appropriate to use reference counting to describe this situation.
iGC Runtime Objective-C Runtime
Frameworks & Libraries
iGC Managed Application
Platform OS Services
- 8 -
In general, iGC maintains two reference counts for a managed object (there is nothing related to Objective-C retain count). One count (LRC)
reflects the number of references from outside the heap. The other (ERC) reflects the number of references from within the heap. If both counts
(LRC and ERC) of an object reach zero, then the object is freed immediately. If LRC is not zero, then the object is root for tracing in garbage
collection. Unreachable objects are of zero LRC and non-zero ERC.
These two counts, with some other control data, are stored in a special area separate from user-visible content of Objective-C objects. The area
is packed and efficient for collector to scan. When garbage collection is triggered, the collector scans this area instead scanning or traversing all
objects to determine roots. So the process of root determination is very fast compared to traditional GCs, which need to invoke system services
to suspend threads, wait for synchronizations of multiple threads, avoid unsafe kick-in points, scan stacks (which may be deeply nested), etc.
Several points of note regarding the collector:
The collector is fully-concurrent. That is, it runs concurrently in a dedicated background thread, and never suspends any of your app
threads. Write barriers are used to ensure the collector see the correct graph while app threads are constantly changing them.
The system automatically triggers garbage collection if some conditions are reached, like memory threshold. And you can trigger garbage
collection explicitly with some parameters, altering its behaviour.
After the collector determines unreachable objects, each unreachable object is given a chance to declare a relationship of dependence for
the process of destructing the object, and then the collector will figure out a reclamation ordering that satisfies all dependence
requirements.
iGC has no "finalizer" concept, as is the case with some traditional GCs. Only destructor in C++ or [dealloc] method in Objective-C is
associated with the lifetime of an object. The collector guarantees they are executed only once, even with resurrections.
Enabling Garbage Collection You can mix iGC code with non-GC code within an iOS App project. If you use C++ or Objective-C++ smart pointer techniques, you don’t even
need to make patches on existing compilers. After applying patches to Xcode compilers, including GCC-4.2 and LLVM 3.0, you can use
"-fobjc-gc" compiler flag to turn on iGC garbage collection for iOS platform.
Stacks Globals
Managed Heap Unmanaged memory
0/1
1/0
0/2
0/1 0/1
1/1
1/0
- 9 -
NOTE: We reuse this flag in iOS, while in Mac OS X it is used to enable libauto conservative GC. The flag "-fobjc-gc-only" is still forbidden in iGC
for iOS.
For using iGC with LLVM 3.0 Automatic Reference Counting (ARC), you can use the "-fobjc-arc-gc" compiler flag to turn garbage collection
on. We use the term "ARCGC" mode for using iGC with ARC. Also, you can add "-fobjc-arc-gc-compatible" compiler flag for recompilation of
existing ARC source code.
NOTE: GCC-4.2 doesn’t support ARC, so ARCGC currently can only be used in LLVM 3.0 compiler.
NOTE: Alternatively, you can use both compiler flags "-fobjc-arc" and "-fobjc-gc" to turn on ARCGC. But notice that Xcode IDE will remove the
ARC "-fobjc-arc" flag if it detects either "–fobjc-gc" or "-fobjc-gc-only" is on. So we recommend the use of "-fobjc-arc-gc".
To link in iGC static library, you need to add "-u __iGC__" and "-liGC" to your Linker Flags and provide correct library search paths.
Sometimes you need to add "-lstdc++" to include standard c++ library.
NOTE: For ARCGC mode, in order to link in Apple’s ARC wrapper library for pre-iOS5 platforms, you need to add "-fobjc-arc" or
"-fojb-arc-gc" to your Linker Flags.
You can disable GC or ARCGC for iOS with the compiler flag "-fno-objc-gc" or "–fno-objc-arc". The last appearance of flags wins. We
don’t provide the corresponding "-fno-objc-arc-gc" flag, since it is not necessary. Your code can use macro __OBJC_GC__ to check if GC
is enabled, and use __has_feature(objc_arc_gc) to check for ARCGC mode.
See document "installation.pdf" in the iGC SDK for more detailed instructions.
Features & Specs
iGC provides you with accurate garbage collection for the iOS platforms. You can write your iOS managed application in Objective-C,
Objective-C++ and C++ languages. This fully-concurrent collector runs in a dedicated background thread. It never suspends your application
threads, giving you a very smooth experience and maintaining the responsiveness of your UI apps. Linear allocation gives you an option to boost
your app’s speed by 4x-6x times faster if it contains massive small-size objects.
Main Features:
Accurate collection – iGC is able to accurately identify all required references for garbage collection.
Deterministic reclamation – when the last effective reference to an object goes away, the object is immediately destructed.
Reclamation ordering control – Let you declare a dependence relationship for the process of destructing objects, and iGC will figure out a
reclamation ordering that satisfies all dependence requirements.
Pause-less – This fully-concurrent collector never suspend your works, maintaining high responsiveness of your UI apps.
- 10 -
Compatibility – using the existing iOS frameworks and libraries, maintaining the same RC behaviour and reclamation ordering even if
objects are referenced by cycles.
Technical Details – platforms & devtools
Provide patches to GCC-4.2 and LLVM 3.0 to support GC for iOS platform with or without ARC.
Support Xcode development tools from "iPhone SDK 3.2 Final with Xcode 3.2.2 for Snow Leopard (10.6.0)" to the latest version.
Running on iOS platforms from version 3.0 at least.
Support weak reference (using __weak keyword) to remove cycles at design time for all iOS versions.
Support zeroing weak reference C API for all iOS versions.
Support zeroing weak reference using __autoweak keyword in LLVM 3.0 compiler with ARC.
Your source code is directly compiled into native ARM machine code, no virtual machine.
Pointers are still pointers except ivars operations are emitted with write barrier routines.
Technical Details – reclamation
You can send a [dealloc] message directly or a safer [destruct] message to destruct a live object safely.
Solve the stack overflow issue of deeply nested destruction, which lurks in C++ RAII, reference counting, etc.
Use one cleanup routine instead of a pair of "finalizer" and "destructor" methods, which is complicated and error prone.
Allows resurrection multiple times on an object.
Automatically detects resurrections by the system, which is constantly monitoring ivar assignments.
You can safely access other objects in your destructor, which is impossible in traditional GC without reclamation ordering control.
You can use "strong reference" to retain the target object for safe access from [dealloc] method.
Most cycles formed by existing MRR objects can be detected, and you can use a non-intrusive way (no changes to class implementation
code) to help the system reclaim them in a safe order.
You can associate multiple destructors at runtime to a managed object, including primitive types.
Technical Details – Misc
- 11 -
You can use C++ smart pointer to reference an object’s interior, undifferentiated the same as to the head of the object.
The "interior => head" lookup mechanism is almost zero-cost, making it possible for applying interior pointer to frequent RC updates.
Allows multiple-inheritance, embedded object as a field, object array, etc., saving space and unnecessary indirect references costs.
You can have native C/C++ types and primitives under automatic management as a single object or an array.
The count in iGC is almost 64-bit, reducing the chance of count overflow.
You can use Linear Pool to perform linear allocation (bumper allocation) to create massive small-sized objects. These objects can be moved
around by the system when safe. Objects allocated from thread private pool can be shared between threads.
You can switch back to pure reference counting by replacing the static library libiGC.a with libiGC_RR.a, which does not contain any GC
code. Once you are sure your app hasn’t any reference cycles, you are free to use this feature (some performance boost may be lost).
Performance Testing
In this section, we will give a quick look at the performance testing of iGC, including GCbench testing, pause-less testing, and GC throughputs.
GCBench testing GCBench is a widely-used testing program for GC performance. Basically, it creates large amounts
of garbage nodes of binary trees with various depths and object lifetimes. It does not create
circular reference, so that it can be used for reference counting testing as well as for real cycle
collectors. We have built several GCBench testing programs using different memory management
methods. The execution times of them are measured and compared. Here is a chart of the
standardized results from iPod Touch 2G 3.1.3 (7E18) and iPod Touch 4G 4.3.5 (8L1). It shows
significant performance boost by using iGC in this program.
Pause-less testing iGC shares the same core of HnxGC. Here we
present the testing result of HnxGC on Win32
platforms instead (because we don’t have any
other iOS GCs at hand). In this testing program,
an event is raised every 5 milliseconds with 1
millisecond resolution. Time elapsed between
- 12 -
two consecutive events are measured, which means in ideal situation the event interval should be 5 milliseconds. Here is the resulting graph of
programs using HnxGC, Microsoft .NET and Boehm conservative GC, comparing with an ideal (idle running, no garbage collection) program. We
can see that the result of HnxGC is indistinguishable from the ideal one.
GC Throughputs This program tests how the size of live objects in heap affects the throughputs of garbage collections.
It shows that although the time spent on object traversal are proportional to the size of live objects, HnxGC outperforms other competitors
significantly, up to almost 1000x(Boehm’s GC) and 100x (.NET CLR) times faster, when the amount of live objects is small.
FAQs
What languages does iGC support?
iGC supports Objective-C, Objective-C++, and C++.
What’s the difference between HnxGC and iGC?
HnxGC is designed for C++ based cross-platform applications. iGC is for iOS platforms, primarily for Objective-C apps (also supports
Objective-C++ and C++). HnxGC and iGC share the same runtime core.
Why not replace weak reference with zeroing weak reference?
Zeroing weak reference is not zero-cost. The synchronization between application threads and the collector cannot be overlooked, since
application thread may convert an object back to active via weak reference. App code must take special care to ensure correctness between
threads. Therefore, zeroing weak reference cannot be used in the same way of non-zeroing weak reference in programming grammar.
iGC weak reference (non-zeroing) operates as it was used in traditional RC for design time cycle-breaking. It is a raw pointer, and iGC doesn’t
monitor it. It is zero cost, and we recommend use it freely as in traditional manual management.
In a hybrid GC (like iGC), weak references are widely used to avoid cyclic references. The performance impact from weak reference is more
important than in a non-RC garbage collection environment, where the uses of weak references are fewer.
- 13 -
Can I use zeroing weak reference for pre-iOS5 platforms?
Yes. Zeroing weak reference is provided by iGC runtime. It does not depend on Apple’s iOS 5 runtime. The keyword __autoweak requires the
LLVM 3.0 compiler, which is provided by Xcode 4.2 and iOS SDK 5. You must install iOS 5 devtools to build app for pre-iOS 5 platforms.
Why we need a runtime collector instead a dev-tool that detects cycles?
If you use dev-tools to detect cycles, you have to modify your source code to eliminate cycles. Sometime it is easy, sometime it is not. You have
to change some class definitions with weak ivars, or add some code to break cycles at proper runtime.
Using a runtime collector, you don’t need to inspect every related data structures in detail to figure out how to break cycles; just let the system
to collect cycles, and you can explicitly invoke GC to after massive uses of objects. It shortens your software development cycles.
Furthermore, garbage collection can boost the performance of your apps. Sometimes the boost is significant for a complicate data structure with
massive small-sized objects.
What’s Direct Kill?
If an object is mistakenly retained or referenced by other long-lived objects or code, automatic memory management system will think it may be
actively used by others. To reclaim these types of unused objects, iGC provides “Direct Kill” feature, which allows you explicitly reclaim a live
object and in turn release resources it occupies directly or indirectly.
- 14 -
Programming Guide
The following sections describe programming changes from existing iOS app development for writing an iGC managed app. For something not
mentioned in this document, they are the same as before. For example, the statement [[Foo alloc] init] creates an iGC managed instance
of class Foo.
Object References
Once your Objective-C source code is compiled by an iGC compiler with garbage collection enabled, classes defined in the source code are
managed classes, and code accessing ivars are monitored by the iGC runtime.
In iGC, when assigning an object reference to an ivar, the system will automatically maintain reference counts of related objects and invoke write
barrier routines, if necessary. Therefore, you don’t need to send retain/release messages for ivars assignments.
For other operations on non-ivar references, such as function return value and parameters, local and global variables, fields of unmanaged
objects, etc., you need to use traditional ways to retain and release objects involved. For example, when assigning an object reference to a local
variable (auto variable) in a function, you need to explicitly send a "release" message to the old value, and send a "retain" message to the new
value. One exception is in ARCGC mode, since ARC compiler will generate [retain/release] calls for you.
There are four types of references that can be used to declare ivars and property of an Objective-C class. They are "managed", "weak", “strong",
and "zeroing weak". Details of these 4 reference types are described below.
Managed reference In iGC managed code, a default ivar/property declaration is a "managed reference". For example, in the code below, ivar "_next" and property
"next" are both managed references.
@interface Node : NSObject { Node * _next; } @property (nonatomic, assign) Node *next; @end @implementation Node @synthesize next = _next; @end
iGC runtime monitors assignments to “managed references" to maintain correct retain counts, and follow them in tracing garbage collection.
Cycles formed by "managed references" will be collected automatically.
A "managed reference" holds the target object alive except when the containing object is a member of unreachable cycles being collected by
garbage collector. Use "strong reference" instead to demand a reclamation ordering requests, to enforce the target is accessible in [dealloc]
method.
- 15 -
Strong reference A strong reference is a special managed reference that holds the target object alive even when the containing object is being destructed as
unreachable cycles. For example, if object A points to object B via a strong reference, then when both A and B become unreachable, either as
member of a cycle or being referenced by cycles, the collector will destruct object A prior to object B. Therefore, it is safe to access object B in
the [dealloc] of object A.
Only a property can be declared as a "strong reference" for compatibility reasons. A property with the "retain" attribute is a "strong reference".
@interface Node : NSObject { Node * _next; } @property (nonatomic, retain) Node * next; @end @implementation Node @synthesize next = _next; @end
Notice that, if "strong references" constitute a cycle, that raises a circular demands for reclamation ordering. This kind of situation should be
avoided whenever possible. If this situation did happen, you can use iGC runtime API _hnxgc_set_cycle_breaker() to overcome this problem by
choosing some objects be reclaimed first.
Weak reference Weak references in iGC are *not* monitored by the system. They are raw pointers without any associated action emitted. Weak reference ivar
and property must be declared explicitly with the __weak keyword. For example,
@interface Node : NSObject { __weak Node * _next; } @property (nonatomic, assign) __weak Node * next; @end @implementation Node @synthesize next = _next; @end
A weak reference does not hold target objects alive. To prevent an object from being reclaimed by the system, there must be at least one
effective (non-weak) reference path to the object, or explicitly retain it by sending retain message.
Zeroing weak reference A "zeroing weak reference" is a special weak reference. Its content will be auto-zeroed by the system when the target object is reclaimed.
Synchronization rules between application threads and the collector should be carefully followed, because while an application thread is loading
value from a "zeroing weak reference", the value may be "zeroing" by the collector. So, the loading operation should be atomic and returning a
non-weak value.
Although, you can use C API _hnxgc_weakref_xxx() to manipulate "zeroing weak reference", such as loading, storing, etc., the iGC LLVM 3.0
compiler provides __autoweak keyword to simplify this work as showed below.
- 16 -
@interface Node : NSObject {
__autoweak Node * _next; } @property (nonatomic, assign) __autoweak Node *next; @end @implementation Node @synthesize next = _next; @end
Summary "Managed reference" retains the target object alive, and cycles formed by managed references can be automatically collected. However, it
doesn't enforce any reclamation ordering for unreachable cycles, thus the target object of a managed reference may has been destructed before
the [dealloc] cleanup method of the containing object. "Strong reference" guarantees the target object remains alive for the cleanup method by
demanding a reclamation ordering to iGC system. "Weak reference" can be used to avoid cycles at design time to collect objects immediately.
"Zeroing weak reference" makes your code safe, but does introduce some extra runtime cost compared to non-zeroing weak.
ARCGC_C & Reference Mapping ARCGC_Compatible(ARCGC_C) mode is designed to reuse ARC source code without change in iGC garbage collection environment. It maps ARC
ivar and property attributes and qualifiers to iGC equivalents. For example, ARC @property(strong) is mapped to iGC managed reference.
To enter ARCGC_Compatible mode, add a compiler flag -fobjc-arc-gc-compatible in addition to existing ARCGC flag -fobjc-arc-gc in project
settings.
Below is a table showing reference equivalence of various modes.
- 17 -
- 18 -
- 19 -
Object Reclamation
The cleanup routine In iGC, to define a cleanup routine with an object, you can merely define a [dealloc] method in Objective-C or a destructor in C++. The grammar
is the same as in standard Objective-C and C++ languages. In iGC, there is no concept of "finalizer" or the like as in many other GCs.
Remember, with garbage collection enabled, you should not send [release] message to ivars in your [dealloc] method, as iGC has already
handled that for ivars. Additionally, for ARCGC mode, you don’t need to invoke the [super dealloc] method call, since ARC will do that for you.
- (void)dealloc { printf("[Object (%p) dealloc]\n", self);
free(data); // essential cleanup jobs
#if !defined(__OBJC_GC__) [aIvar release]; // for manual management
#endif #if !__has_feature(objc_arc) [super dealloc]; // for non-arc #endif }
Immediate reclamation When an object loses all effective references to it, the system will destruct it immediately.
Ivars of an object become invalid just after the object has been destructed. Thus, child objects lose references after destruction of the parent
object. Notice that the ivar references are not dropped during the destruction. That is different from previous manual management which drops
member references manually in the [dealloc] method. One of the main reasons for this design is to avoid the nesting of destructions, which
may cause stack overflow in some large data structures. For example, a single linked list with more than 30,000 nodes. Another reason is for
performance, as references dropped by the system are usually slightly faster than in a user-defined [dealloc] method. If you need, you can
assign nil to the ivar reference in your [dealloc] method. The child will be released immediately. If there are no other references to the child,
the child will be destructed nested inside your [dealloc] method call.
Acyclic group of objects can be destructed immediately by destructing the head object of the group. However, if an acyclic group of objects are
referenced by a cycle, then these objects are not destructed immediately. You can use (1) weak reference to avoid cyclic graph at design time, or
(2) assign nil to ivars at runtime to break existing cycles. (3) If you cannot modify your class interface, or access some private ivars, you can use
the following approach to destruct a live object to break a cycle.
You can send an iGC specific [destruct] message to a live object to destruct the object immediately
You can directly send a [dealloc] message to a live object to destruct the object immediately (NOTE: Apple iOS UI framework did do in this way,
although in their document they recommend not do this). The [dealloc] message directly sent should stand-in a [release] message and
balance with a [retain] message as shown in the following iGC code snippet (non-arc mode).
- 20 -
Node *a = [Node alloc]; Node *b = [Node alloc];
a->next = b; b->next = a;
[a destruct]; // immediately execute [dealloc] of 'a' and 'b' [a destruct]; // it is safe to send multiple times, only the first [a destruct]; // one is effective
[b release]; [a release];
Alternative, you can use C API _hnxgc_destruct_object() or C++ gcdelete keyword to do the same thing.
NOTE: LLVM 3.0 ARC disallows you to send [dealloc] message. But, in ARCGC mode, this limitation is removed after applying a patch to SDK
headers.
Reclamation ordering Many traditional GCs collect unreachable objects in an unpredictable order. That means, in the [dealloc] method, that the target object
referenced by an ivar may have been destructed even though you hold an effective ivar reference to it. Methods provided by the destructed
object may malfunction.
iGC provides a way to let you control the reclamation ordering of unreachable objects. You can define an "OnReclaim" call back method in your
C++ class, and when the collector has determined all unreachable objects, the system will invoke the "OnReclaim" method of each unreachable
object. In the method, you can use API to declare a dependences relationship for the process of destructing the object. For example, you can
declare that the process of destructing object A depends on object B and C, which may be directly or indirectly referenced. Object A could be
another object, not limited to the "this" pointer of the "OnReclaim" method. After all unreachable objects have claimed their dependence
requirements, the system will figure out a reclamation ordering that satisfies all these requirements. Therefore, you know the objects that you
want to use in your cleanup routine are guaranteed to be alive, and you are free to access them the same as if they were not in a cleanup routine.
For Objective-C and Objective-C++ language, you can use "strong reference" ivar to retain the target object alive during the destruction of the
containing object.
Resurrection In iGC, once the destruction of an object is started, the object cannot be reverted to live again. Because partial destruction may change the
consistency of the internal status of the object, restoring its status to live may require the introduction of complicated API and high runtime costs.
So, we just disallow it and provide an alternative solution.
You can resurrect an object that is going to be reclaimed. In the "OnReclaim" method described previously, you can resurrect another object or
itself by assigning the object to an effective reference to make it reachable again. The collector will monitor that change and put the object and
its descendants back to live again, before real destruction starts.
There is no limitation on the number of resurrections for a single object. Once an object is resurrected, its status is reverted back to original, as
if nothing has happened.
- 21 -
Dynamic associated destructor At runtime, you can dynamically associate multiple destructors to an existing managed object, including primitives. For example, suppose you
create a managed integer array, you can associate a destructor to perform some cleanup tasks for it. NOTE: We do not use any hash table or the
like to implement this feature, so the negative performance impacts on object reclamation are minimized almost to zero.
Reclaim circular depended cycles Garbage collector can reclaim circular referenced objects without difficulty, but how should those that are circular depended be handled? For
example, suppose object A and B both request that the system keep each other alive for processing their cleanup routine. In another example,
suppose some design pattern sends "retain" messages to both objects A and B, to keep those objects alive, and sends "release" messages in the
[dealloc] methods of A and B. This makes it impossible to determine a correct reclamation order for objects A and B.
iGC provides a mechanism to address this issue. You don’t need to alter your designs or class layouts. Once you know which objects form circular
dependence cycles by studying debug outputs, you can use API _hnxgc_set_cycle_breaker(obj) to tell the system where to start reclamation for
these cycles. Then, when the collector detects these unreachable cycles, it knows where to start to reclaim the circular dependence cycles.
Linear Pool
Linear Pool is a mechanism that can be used in C++ and Objective-C/C++ to provide fast linear (bumper) allocation for small-sized managed
objects. As illustrated in the figure below, objects are allocated linearly from the pool. The type of allocation is very fast, and unused objects are
freed automatically by the GC system, not individually by the application threads. Thus, application threads gain the maximum performance
benefit from it
Features & tech specs Different sized objects can be allocated linearly from the same pool.
You can create multiple pools in a process.
Object allocation from a pool is not thread safe, but once the object is created, it is thread safe like other usual objects.
If a pool is shared between multiple threads, i.e. not a per-thread private pool, you have to use external synchronizations to ensure safety
for the operation of object allocation.
Objects inside a pool can reference other objects or vice versa, regardless of whether they exist outside the pool or in other pools.
… …
Obj 1 Head Obj n-1 Obj n Free SpaceObj 2
- 22 -
The maximum size of an object in a pool is close to 64KB, though we recommend making them not larger than 2KB for performance
considerations. There is no limitation on the number of objects or on total object size in a pool.
Objects are not freed individually; they are freed as a group when all objects inside the group are unreachable or evacuated.
Objects can be evacuated from a pool, i.e., they are moved out of the pool and become a standalone object. The system will automatically
update related references when objects move.
You can explicitly request an evacuation when it is safe.
The pool itself is also auto managed; it will be reclaimed when there is no reference to the pool or to any objects inside the pool.
Objects in pool should not contain any cleanup method, and they should not reference RC type standalone objects.
Create a linear pool You can use C API _hnxgc_linearpool_create() to create a pool. It returns a locked handle to the newly-created pool. Or you can use a
wrapper C++ class, e.g. gcptr<GCLinearPool> pPool = GCLinearPool::Create();
Create an object from a pool C++ with wrapper class:
gcptr<CNode> p = gcnew_pool(pPool) CNode;
Objective-C:
Node * p = [Node createFromPool:hPool];
An object returned from [createFromPool] is a weak reference, not retained. If you want to retain it longer than the lifetime of the pool, you
should make at least one effective reference to it before all references are dropped, e.g., send a [retain] message to it, or assign it to an ivar.
After objects are effectively referenced or retained, you can invoke
_hnxgc_linearpool_safetorelease(hPool)
to let the system to release space of non-referenced objects in the pool.
Drop references to pool or objects References to pools or objects in pools are normal references, the same as for any general standalone objects. You can drop them as usual.
- 23 -
Evacuate objects from a pool You can invoke
_hnxgc_linearpool_evacuate(hPool);
to move all live objects out of the specific pool. During the service call, the system will update related references to new object locations. All
spaces in the pool are released.
The time taken by this operation varies depending on some factors, such as the size of active objects in the pool and the number of related
references, etc.
- 24 -
API References
- 25 -
Predefined Macros
__OBJC_GC__
defined if garbage collection is enabled for iOS platforms
__has_feature(objc_arc)
true if it is in ARC, ARCGC, or ARCGC_Compatible mode
__has_feature(objc_arc_gc)
true if it is in ARCGC or ARCGC_Compatible mode
__has_feature(objc_arc_gc_compatible)
true if it is in ARCGC_Compatible mode
__has_feature(objc_hnxgc)
true if it is in iGC garbage collection is enabled, including in ARCGC and ARCGC_Compatible mode
__has_feature(objc_hnx)
true if the compiler is iGC LLVM 3.0
- 26 -
Objective-C Methods
destruct
destruct a live object immediately
Declaration: @interface NSObject ()
- (void)destruct;
@end
Example: id p = [[Foo alloc]init];
...
[p destruct]; // immediately destruct `p'
...
[p release];
createFromPool
allocate a managed object from specified linear pool
Declaration: @interface NSObject ()
+ (__weak id)createFromPool:(uintptr_t)pool;
@end
Example: @interface Node: NSObject {
Node * next;
}
@end
uintptr_t hPool = _hnxgc_linearpool_create();
Node * p = [[Node createFromPool:hPool] retain];
...
[p release];
- 27 -
__weak
Objective-C keyword to declare a weak (non-zeroing) ivar or property. <see "Programming Guide: Object Reference">
__autoweak
Objective-C keyword to declare an auto-zeroing weak ivar or property. <see "Programming Guide: Object Reference">
- 28 -
C Functions
_hnxgc_collect
explicitly request tracing garbage collection
Declaration: void _hnxgc_collect();
_hnxgc_destruct_object
safely destruct a live object
Declaration: void _hnxgc_destruct_object (void * obj);
_hnxgc_add_memory_pressure
notify the system to perform garbage collection more frequently.
Declaration: void _hnxgc_add_memory_pressure(size_t size, bool bRemove);
Example: int nExtraMemSize = 64 * 1024;
+ (id)alloc {
... // allocate some memory for this object
_hnxgc_add_memory_pressure(nExtraMemSize, 0); // increase
memory pressure
...
}
- (void)dealloc {
... // free the associated memory
_hnxgc_add_memory_pressure(nExtraMemSize, 1); // reduce memory
pressure
...
}
- 29 -
_hnxgc_did_receive_memory_warning
notify iGC that the memory available is very low
Declaration: void _hnxgc_did_receive_memory_warning();
Example: - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
...
_hnxgc_did_receive_memory_warning();
}
_hnxgc_set_trace_level
trace iGC behaviors, such as performing GC, allocate objects and reclaim garbages
Declaration: int _hnxgc_set_trace_level(int level);
// returns: existing trace level
// input: new trace level [0 : not trace, 1 - 999: the high value the
more print-outs]
Example: _hnxgc_set_trace_level(200);
_hnxgc_set_cycle_breaker
set an object where iGC start to reclaim dependence cycles
Declaration: void _hnxgc_set_cycle_breaker (void * obj);
_hnxgc_set_nonrc
set an object to non-RC state
NOTE: ivar references to non-RC object are traced but do not contribute to reference count, so the object will
- 30 -
not be reclaimed immediately after use (can only be reclaimed by garbage collection).
Declaration: void _hnxgc_set_nonrc(void * obj);
_hnxgc_weakref_allocate
allocate a zeroing weak reference slot
Declaration: uintptr_t _hnxgc_weakref_allocate();
_hnxgc_weakref_deallocate
free a zeroing weak reference slot
Declaration: void _hnxgc_weakref_deallocate(uintptr_t slot);
_hnxgc_weakref_read
return a "retained" reference from a zeroing weak reference slot
Declaration: void * _hnxgc_weakref_read(uintptr_t slot);
_hnxgc_weakref_write
assign a reference to a zeroing weak reference slot
Declaration: void _hnxgc_weakref_write(uintptr_t slot, void * obj);
<General C API>
manipulate managed objects in C, C++, Objective-C and Objective-C++ langugages, see HnxGC documents for more details.
- 31 -
C++ API
gcptr<T>::i
smart pointer for managed ivar reference
Declaration: gcptr<T>::i <ivar name> Example: @interface Node : NSObject {
gcptr<Node>::i nextNode;
}
@end
gcptr<T>
flexible smart pointer for non-ivar reference
Declaration: gcptr<T> <ivar name>
gcnew_i
create C++ smart pointer style objective-C object
Declaration: gcnew_i <expression returns a retained object> Example: gcptr<Node> pNode = gcnew_i [Node alloc];
gcdelete
safely destruct a live object
Example: Node * pNode = [[Node alloc] init];
...
gcdelete pNode;
- 32 -
Example 2: gcptr<Node> pNode = gcnew_i [[Node alloc] init];
...
gcdelete pNode;
<General C++ API>
manipulate managed objects in C++ and Objective-C++ languages, see HnxGC documents for more details.
- 33 -
Articles
The following will contain some selected articles regarding iGC / HnxGC. Some of them are advanced and may not be updated with the changes
of new release of iGC / HnxGC.
- 34 -
Maintaining existing RC cleanup ordering
Adding GC to existing RC-based system brings in some new challenges. In this section, we will describe the problem of cleanup ordering and how
it was solved in iGC.
The problem Reference counting has implied a very strong ordering on cleanup of unused objects. Naively switching RC system to GC will break this implicit
behaviour on which many existing RC codes depend. For instance, if existing RC-based objects (acyclic) are referenced by cyclic garbage, then
they can only be collected by GC and may be disposed in a wrong ordering different from existing RC code. Therefore, some existing code may
crash because in their cleanup code, they may access some other objects which have been destructed by GC as effective reference cannot keep
object alive during cleanup code.
Therefore, in order to reuse the existing RC-base code, we must maintain the same cleanup ordering of those RC-based acyclic objects.
Discarded attempts One attempt to solve this problem is to treat RC-based objects as native non-managed, but this way is inefficient and objects are beyond the
management of GC system causing cycles of them uncollectible.
Some GC systems (such as Boehm GC) only cleanup unreachable objects that are not referenced by
others, then in turn expect more objects become eligible for this rule. Using this way to maintain cleanup
ordering has at least two issues: (1) the cleanup of cycles and their descendants are skipped undesirably,
e.g. in Figure-1, if C2 needs cleanup, then because C2 references C1, A1 to A4, all the cleanup routines of
these objects are not executed under this rule; (2) if the GC system does not immediately reclaim zero-RC
objects, then some orderings enforced by RC-based code are violated. For example, RC can enforce a
cleanup ordering of A3 prior to A4 by explicitly nullifying reference from A2 to A3 in A2’s cleanup code. In
conclusion, such GCs are not suitable for a RC compatible system.
iGC solution In iGC, RC-based objects are under the management of the system. Existing RC code (retain/release
message) are replaced with maintaining a per-object count that represents the number of references from
root-set. That is, references from original RC-based objects are treated as coming from root-set, thus the
referents will not be collected by normal GC when they become unreachable. After GC collects other cycles that are referencing them, the
reference counts of these RC-based objects will drop to zero, then the objects will be collected consequently and the ordering of cleanup will be
exactly the same as original RC.
For example, as showed in Figure-1, unreachable RC-based objects A2, A3 and A4 are treated as being referenced by root-set. They are not
collected until C1, C2 and A1 are collected by GC. After GC collects and destructs A1, then objects A2, A3 and A4 will consequently lose their last
references and be destructed in the same order as in the original RC-based system.
See also: "Aggressive garbage collection" – collect cycles of existing RC objects
C2C1
GC Collected
Same RC Order
A1
A2
A4
A3
Unreachable Garbage
Figure 1
- 35 -
Solving stack overflow due to deep-nested destructions
Many C++ programmers may be unaware of a bug residing in their data structures. Consider the following innocent looking code which defines
a node for a linked list:
struct Foo { Foo * m_pNext; ~Foo() { delete m_pNext; } };
As is typical, this structure contains the logic for cleaning up the linked list in its destructor by deleting its sibling node. The sibling node then
deletes its sibling and so on, until the entire linked list is deleted.
A typical routine for constructing and using the linked list might look something like this:
#define NESTED_DEPTH 100000 static void doTest() { // create a singlely-linked list Foo * pFirst = 0; for (int i = 0; i < NESTED_DEPTH; i++) { Foo * pNode = new Foo; pNode->m_pNext = pFirst; pFirst = pNode; } // dispose the list delete pFirst; }
When it comes time to delete the list, clean up is invoked by deleting the first node. In applications where there are a relatively small number of
nodes, this code works just fine. But what happens when the length of the linked list is really long such as in the example above where there are
100,000 nodes?
Since Foo's destructor causes a stack based, depth first traversal of all of the nodes in the data structure, the traversal of such a large topology
will overflow the call stack causing a stack overflow exception. This problem can also occur on smaller topologies when the destructor requires a
larger stack frame, e.g. when the destructor contains a fixed sized array. The worse part is that this bug may not show up until the code is being
used in a shipped application handling massive amounts of data.
In HnxGC, this problem is easily solved by rewriting the code as shown here:
struct Foo { HNXGC_ENABLE(Foo) gcptr<Foo> m_pNext; // replace Foo * with gcptr<Foo> ~Foo() { // removed call to delete-deletion of m_pNext is automatically // handled by gcptr } };
gcptr is a smart pointer class provided by HnxGC which takes care of the destruction for you. With HnxGC you simply redefine all pointers to your
structure using the templated gcptr class, passing in your structure name as the template parameter.
- 36 -
You then delete the linked list by clearing all pointers to the first node of the data structure as shown here:
#define NESTED_DEPTH 100000 static void doTest() { // create a singlely-linked list gcptr<Foo> pFirst = 0; // replace Foo * with gcptr<foo> for (int i = 0; i < NESTED_DEPTH; i++) { gcptr<Foo> pNode = gcnew Foo; // replace Foo * with gcptr<foo> pNode->m_pNext = pFirst; pFirst = pNode; } // dispose the list pFirst = 0; // using HnxGC, deletion is performed by simply // removing all references to pFirst // all objects will be destructed before the next // instruction }
Behind the scenes HnxGC decreases the reference count when pFirst is set to 0. When the reference count reaches 0, HnxGC safely deletes the
entire linked list for you. The reason why HnxGC safely deletes the list is because HnxGC deletes each node one by one, thereby releasing the
stack frame after execution of the current destructor before calling the next destructor. This means that the size of the destructor's call stack
does not grow and therefore topologies of any size will be safely deleted. This also results in faster execution than with nested destruction
because the space required for the stack is smaller.
With HnxGC you can finally encapsulate the initialization and clean up logic of your data structures directly in the structure itself without worrying
about stack overflow problems. And because destruction executes immediately upon invoking clean up, HnxGC's garbage collection is
deterministic, as opposed to other implementations where you have little or no control over when clean up occurs. Destruction of circular
references (while not immediate even with HnxGC) is also faster with HnxGC because it avoids the costly suspension of application threads.
Stack overflows during destruction are a serious problem, and can exist across different C++ development frameworks. In traditional C++ it's
common to implement Resource Acquisition Is Initialization (RAII) where by construction and destruction of a resource are encapsulated to take
advantage of the fact that objects on the stack are cleaned up. The problem can also exist in other frameworks which may give the illusion that
they enable safe destruction. For example, Boost's shared_ptr and intrusive_ptr classes define an interface for clean up, but because it's up to
the programmer to implement the destruction logic, one can easily implement the nested destruction problem. Another example is Managed
C++ where, despite the apparent safety of the garbage collected environment, programmers are still free to implement nested destruction which
is executed on a growing call stack just like regular C++.
- 37 -
Choosing new style coding
In new style coding for Objective-C, you don’t write codes explicitly to maintain RC for references from an object. Instead, the underlying runtime
library will do the RC maintenance for you. Using the new style of coding has the following advantages over previous styles:
Reduced code writing workloads
Making more cycles non-sensitive to cleanup ordering
Writing one code for both GC and RC
Reducing your code writing workload Previously, programmers typically used property mechanisms to alleviate the work for manual maintenance of RC. For example, individuals may
use @property(retain) to declare a property and then allow a compiler to generate appropriate accessor methods to perform RC work. But,
since the compiler has no direct interaction with the dealloc method, properties are not automatically released in the dealloc method for you.
So, in a dealloc method you have to release objects directly or invoke accessor with nil as the parameter. If you forget to do this, or do it in
an incorrect way (e.g., releasing a non-retain property), your application may leak or even crash.
In new style coding, runtime library will automatically release property for you. So you can use @property (retain) to declare property as
usual, but in the dealloc method you don’t need to write code to release it manually. The dealloc method should only contain the essential
cleanup code. This allows you to focus on your application logic and lets the system take care of the rest of the work, such as object lifetime
management.
Also, new style coding uses __weak, @property (assign) and @property (retain) keywords to denote specific uses of properties and
pointer fields. This makes codes more readable and the purpose of pointers more clearly distinguishable.
Making more cycles non-sensitive to cleanup ordering In the new style coding the dealloc method only contains essential cleanup code, as the responsibility of releasing referent objects is passed
to the underlying runtime library. If there is no need to do any essential cleanup job, then there is no need to define a dealloc method. This
increases the chance of not define a dealloc method, compared to the previous style where usually there are many dealloc methods that
exist only to perform object releasing work.
If an object doesn’t have a dealloc method, then it is not concerned with any other objects that are alive or not. No other objects should be
kept alive for this object (iGC allows doing release operation on a dead object). Therefore, it gives more freedom to the system in reclamation
ordering of unreachable cycles.
NOTE: In the previous style, if a cycle has been formed, then it is almost impossible to auto-determine a correct cleanup ordering, as dealloc
methods usually have been defined. To cleanup these cyclic objects in a safe order, you must activate the Aggressive GC option and manually
specify where to start.
- 38 -
Writing one code for both GC and RC Once you write code in the new style, your code can be used not only in GC environments, but also in traditional RR (retain/release) based
environments (also known as RC-based in this documentation).
Unlike the built-in GC in Mac OS X, you don’t need to devote a lot of effort into the finalize and dealloc methods, e.g., trying to make it
compatible with both non-deterministic GC and immediately reclaimed RC. In iGC, the runtime behaviour is already compatible with the existing
RR system. Designing a compatible application for both iGC and the existing RR system is straightforward and natural.
You can also roll back your new code to pure RR runtime by simply replacing the iGC library with iGC_RR library without making changes to your
new-style source code, nor any recompilation. Actually, the iGC_RR library is a small wrapper that redirects all implicit RC maintenance to the
iOS Objective-C RR system, including the object releasing works in dealloc methods.
NOTE: You will lose garbage collection benefits if you roll back to the manual retain/release.
Conclusion Using the new style coding for your next application development provides many benefits, and it is easy to switch back and forth between GC
and non-GC.
- 39 -
Advanced Subtle Topics
Access after destruction
The contents of member pointers retain valid
The contents of member pointers must maintain valid (NULL or pointing to a valid object) after destruction. The system may access member
pointers of a destructed object and trace them to other objects directly or indirectly. You should not alter the content of member pointer to an
invalid reference in cleanup routine.
Dead object spaces are not recycled concurrently
When the system is performing garbage collection, some objects may lose their last references and become eligible for reclamation by reference
counting system. These objects will be destructed immediately, but the system does not recycle the memory space in this case. It is safe for
tracing GC to access these dead zero-RC objects.
Reference counting
Zero-RC destruction will *not* be affected by GC
When an object becomes Zero-RC, the system will invoke its destructor and in turn reclaim more Zero-RC descendants. This destruction
behaviour will not be affected by a concurrently running GC, i.e. the RC destruction will not be postponed or skipped.
Aggressive garbage collection References from existing RC-based objects are treated as strong references from root-set. Does it cause cycles involving these references never
be collected? The iGC provides Aggressive Garbage Collection, which can automatically adjust RC contributions from existing RC-based objects,
so the system can detect cycles involving RC-based objects, as well as cycles fully composed of existing RC-based objects.
NOTE: By default, the Aggressive GC feature is turned off due to performance considerations. You have to manually turn on this option to collect
cycles involving existing RC-based objects. Alternatively you can migrate existing RC-based code (modifying it very little) to new style GC-based,
achieving the same goal but faster. To using Aggressive GC, simple replace Link settings in you projects to link “libiGC_AGG.a” instead “libiGC.a”.
C++ Exceptions Your code can throw exceptions in the constructor of a managed object, but should not throw any exception into the destructor. The main reason
is the destructor may be executed in a background collector thread or in other threads; the execution environment may not be the same as what
you expected.
Where GC runs When some pre-defined conditions are reached, the system will trigger the background collector to perform tracing garbage collection. You can
also explicitly invoke garbage collection in any context, including in the destructor of an object that is being destructed.
At runtime, you can instruct the system to perform a final garbage collection upon exiting the application.
- 40 -