Implementing alloc, retain, release, and dealloc
2013-12-16 11:43
309 查看
Implementing alloc, retain, release, and dealloc
Many parts of OS X and iOS are publicly available as open source software at Apple Open Source.1 Asmentioned above, the alloc, retain, release, and dealloc are methods of the NSObject class.within the Foundation Framework, as part of the Cocoa Framework, Unfortunately, the Foundation Framework is not a part of Apple Open Source. Fortunately, because the
Core Foundation Framework is a part of Apple Open Source, the source code for memory management that is used from NSObject is public. But still, without having the implementation of NSObject itself, it is hard to see the whole picture. So let’s check
an alternative source code from GNUstep.2
GNUstep is a compatible implementation with the Cocoa Framework. Although we can’t expect it to be exactly the same as Apple’s implementation, it works in the same manner and the implementation
should be similar. Understanding GNUstep source code helps us guess Apple’s Cocoa implementation.
The alloc Method
Let’s start with the allocmethod of the NSObject class in GNUstep. As a side note, some source codes in this book might be modified to make the important part
clear.
The “alloc” method of the NSObject class is called as in:
id obj = [NSObject alloc];
The implementation of
allocin NSObject.m is shown in Listing
1–1.
Listing 1–1. GNUstep/modules/core/base/Source/NSObject.m alloc
+ (id) alloc { return [self allocWithZone: NSDefaultMallocZone()]; } + (id) allocWithZone: (NSZone*)z { return NSAllocateObject (self, 0, z); }
Inside the allocWithZone: method, an object is allocated with the NSAllocateObject function. The implementation is shown in Listing
1–2.
__________
1 Apple, “Apple open source,”
http://opensource.apple.com/
2 GNUstep, “GNUstep.org,”
http://gnustep.org/
Listing 1–2. GNUstep/Modules/Core/Base/Source/NSObject.m NSAllocateObject
struct obj_layout { NSUInteger retained; }; inline id NSAllocateObject (Class aClass, NSUInteger extraBytes, NSZone *zone) { int size = /* needed size to store the object */ id new = NSZoneMalloc(zone, size); memset(new, 0, size); new = (id)&((struct obj_layout *)new)[1]; }
The NSAllocateObject function calls NSZoneMalloc to allocate a memory area. After that, the area is filled with zero and the area pointer is returned.
NOTE: Originally, NSZone was used to prevent memory fragmentation (Figure
1–7). By switching zones case by case, memory allocation could be more effective.
But nowadays, Objective-C runtime just ignores zones as you can see at “Transition to ARC Release Notes.”3 Because
a recent runtime memory management algorithm is effective enough, using zones is not considered meaningful or worthwhile because of the complexity.
Figure 1–7. Preventing fragmentation using multiple Zones.
By removing NSZone-related code, the alloc method can be simply rewritten as in Listing
1–3.
__________
3 Apple, “Transition to ARC Release Notes.”,
http://developer.apple.com/library/mac/#releasenotes/ObjectiveC/RN-TransitioningToARC/_index.html
Listing 1–3. GNUstep/modules/core/base/Source/NSObject.m alloc simplified
struct obj_layout { NSUInteger retained; }; + (id) alloc { int size = sizeof(struct obj_layout) + size_of_the_object; struct obj_layout *p = (struct obj_layout *)calloc(1, size); return (id)(p + 1); }
Now that you understand how the alloc method works, let’s move on to
retain.
The retain Method
The alloc method returns a memory block filled with zero containing a struct obj_layout header, whichhas a variable “retained” to store the number of references. This number is called the reference count. Figure
1–8 shows the structure of an object in the GNUstep implementation.
Figure 1–8. Memory image of an object returned by alloc
You can get the reference count value by calling the retainCount method.
id obj = [[NSObject alloc] init]; NSLog(@"retainCount=%d", [obj retainCount]); /* * retainCount=1 is displayed. */
Just after alloc is called, the reference count is one. The next source code shows how the retainCount function is implemented in GNUstep.
Listing 1–4. GNUstep/Modules/Core/Base/Source/NSObject.m retainCount
- (NSUInteger) retainCount { return NSExtraRefCount(self) + 1; } inline NSUInteger NSExtraRefCount(id anObject)
{ return ((struct obj_layout *)anObject)[-1].retained; }
The source code searches the header from the object pointer and gets the value of the retained variable (Figure
1–9).
Figure 1–9. Accessing the header from an object
Because the memory block is filled with zero when it is allocated, the value of “retained” is
zero. The retainCount function returns 1 by “NSExtraRefCount(self) + 1”. We can guess that the “retain” or “release” method would modify the value by +1 or -1.
[obj retain];
Let’s check the implementation of the “retain” method, as in Listing
1–5.
Listing 1–5. GNUstep/Modules/Core/Base/Source/NSObject.m retain
- (id) retain { NSIncrementExtraRefCount(self); return self; } inline void NSIncrementExtraRefCount(id anObject) { if (((struct obj_layout *)anObject)[-1].retained == UINT_MAX - 1) [NSException raise: NSInternalInconsistencyException format: @"NSIncrementExtraRefCount() asked to increment too far"]; ((struct obj_layout *)anObject)[-1].retained++; }
Although it has a few lines of code to throw an exception, when the variable “retained” overflows, it is fundamentally incremented by one on the line “retained++”. Next, we
learn the “release” method the functionality of which is opposite to the “retained” method.
The release Method
We can easily guess that the “release” method would have “retained--”. Also, it should have some codes when the value becomes zero.[obj release];
The “release” method is implemented as shown in Listing
1–6.
Listing 1–6. GNUstep/Modules/Core/Base/Source/NSObject.m release
- (void) release { if (NSDecrementExtraRefCountWasZero(self)) [self dealloc]; } BOOL NSDecrementExtraRefCountWasZero(id anObject) { if (((struct obj_layout *)anObject)[-1].retained == 0) { return YES; } else { ((struct obj_layout *)anObject)[-1].retained--; return NO; } }
As we expected, “retained” is decremented by one. If the value is zero, the object will be disposed of by the “dealloc” method. Let’s see how the “dealloc” method is implemented.
The dealloc Method
Listing 1–7 is the implementation of the “dealloc”method.
Listing 1–7. GNUstep/Modules/Core/Base/Source/NSObject.m dealloc
- (void) dealloc { NSDeallocateObject (self); } inline void NSDeallocateObject(id anObject) { struct obj_layout *o = &((struct obj_layout *)anObject)[-1]; free(o); }
It just disposes of a memory block.
We have seen the implementation of alloc, retain, release, and dealloc in GNUstep and have learned the following.
All Objective-C objects have an integer value called the reference count.
The reference count is incremented by one when one of alloc/new/copy/mutableCopy or retain is called.
It is decremented by one when release is called.
Dealloc is called when the integer counter becomes zero.
Next, let’s check the implementation by Apple.
Apple’s Implementation of alloc, retain, release, and dealloc
As I said earlier, the source code of the NSObject class itself is not publicly available. We investigate how the implementation works using an Xcode debugger (lldb)for iOS application. First, set a breakpoint at the NSObject class method alloc. See what happens on the debugger. The following is the list of functions called inside alloc.
+alloc +allocWithZone: class_createInstance calloc
The NSObject class method alloc calls allocWithZone. After that, through the class_createInstance function, which is documented in the Objective-C Runtime reference, the calloc function is called to allocate the memory block.4 There
does not seem to be much difference with the implementation of GNUstep. We can see the source code of class_createInstance function in objc4 library runtime/objc-runtime-new.mm.5
How about NSObject instance methods retainCount, retain, and release? The following functions are called inside.
-retainCount __CFDoExternRefOperation CFBasicHashGetCountOfKey -retain __CFDoExternRefOperation CFBasicHashAddValue
-release __CFDoExternRefOperation CFBasicHashRemoveValue
__________
4 Apple, “Objective-C Runtime Reference,”
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html
5 Apple, “Source Browser,”
http://www.opensource.apple.com/source/objc4/
(Also, -dealloc will be called as well when CFBasicHashRemoveValue returns 0.)
In all the above methods, the __CFDoExternRefOperation function is called. Then the function calls similarly named functions. These functions are public. As you can see, if the function names begin with CF, you can find the source
codes in the Core Foundation Framework. 6 The source code in Listing
1–8 is the simplified __CFDoExternRefOperation implementation in CFRuntime.c.
Listing 1–8. CF/CFRuntime.c __CFDoExternRefOperation
int __CFDoExternRefOperation(uintptr_t op, id obj) { CFBasicHashRef table = get hashtable from obj; int count; switch (op) { case OPERATION_retainCount: count = CFBasicHashGetCountOfKey(table, obj); return count; case OPERATION_retain: CFBasicHashAddValue(table, obj); return obj; case OPERATION_release: count = CFBasicHashRemoveValue(table, obj); return 0 == count; } }
__CFDoExternRefOperation function is a dispatcher, which calls different functions for retainCount, retain, or release. We can guess these methods would be as follows.
- (NSUInteger) retainCount { return (NSUInteger)__CFDoExternRefOperation(OPERATION_retainCount, self); } - (id) retain { return (id)__CFDoExternRefOperation(OPERATION_retain, self); } - (void) release { return __CFDoExternRefOperation(OPERATION_release, self); }
__________
6 Apple, “Source Browser”,
http://www.opensource.apple.com/source/CF/
As you can see in the __CFDoExternRefOperation function above, Apple’s implementation seems to handle the reference count by a hash table (reference counter table) as shown in Figure
1–10.
Figure 1–10. Managing Reference Counts with a hash table
In the GNUstep implementation, reference counts are in the header of each object’s memory block. But in Apple–s implementation, all the reference counts are stored in entries of a hash table. Although
GNUstep implementation looks simpler and faster, there might be some merit to Apple’s as well.
Here are the benefits if reference counts are stored in each object’s header as in GNUstep’s implementation:
Fewer codes.
It is quite simple to manage the lifetime, because each memory area of the reference count itself is included in the object memory area.
How about if reference counts are stored in a hash table as in Apple’s?
Each object doesn’t have a header, thus there is no need to worry about alignment issues for the header area.
By iterating through the hash table entries, memory blocks for each object are reachable.
The latter is especially useful for debugging. When the memory area of some objects is broken and the table is still there, the debugger can reach the objects’ pointers (Figure
1–11).
Figure 1–11. Finding objects in the Reference Count table
Also, to detect memory leaks, instruments check the entries of the table and determine whether someone has ownership of each object.
That’s it for Apple’s implementation. Now that we have a better understanding of how Apple has implemented things, there is one more item to learn regarding memory management in Objective-C: autorelease.
相关文章推荐
- retain和release倒底怎么玩?
- Objective-C - retain release autorelease
- cocos2dx中Ref的 retain()和release()的区别
- object-c的Retain and Release(保留与释放)
- Linked dylibs built for GC-only but object files built for retain/release for architecture x86_64
- 内存管理autorelease,retain,copy和assign的set方法和含义
- retain和release倒底怎么玩?
- ios内存管理1-retain和release的简单使用
- cocos2dx中retain和release
- release, retain, autorelease 与 AT, MT, AMT
- (ios实战):retain,copy,assign及autorelease ,strong,weak
- Object -c基础知识(5)--release 之后 retainCount为何为1
- Cocos2dx 之retain ,release
- object-c的Retain and Release(保留与释放)
- Linked dylibs built for GC-only but object files built for retain/release for architecture x86_64
- object-c的Retain and Release(保留与释放)
- 【内存管理-问题实例】为什么执行了numberOfRowsInSection方法后,dataArray的retainCount就少了一个? 谁把它 release了?
- 黑箱中的 retain 和 release
- [转]Objective-C的@property 详解(ios,iphone,xcode,retain,release,assign,copy)
- 【OC学习-11】ARC和内存管理里面的alloc、assign、new、retain、copy、mutableCopy、release说明