MRC内存管理原则
1. You have ownership of any objects you create.
2. You can take ownership of an object using retain.
3. When no longer needed, you must relinquish ownership of an object you own.
4. You must not relinquish ownership of an object you don’t own.
Action for Objective-C Object | Objective-C Method |
---|---|
Create and have ownership of it | alloc/new/copy/mutableCopy group |
Take ownership of it | retian |
Relinquish it | release |
Dispose of it | dealloc |
调用者持有
Relinquishing Ownership of a Retained Object. 下面的例子将函数将自己持有的obj, 通过return传递给了调用者,由调用者来来持有此变量
- (id)allocObject { /* - You create an object and have ownership. */ id obj = [[NSObject alloc] init]; /* - At this moment, this method has ownership of the object. */ return obj; }
调用者不持有
通过autorelease, 可以让调用者不持有该对象. Autorelease offers a mechanism to relinquish objects properly when the lifetime of the objects has ended.自动释放提供了一种, 当对象生命周期结束时,自动释放的机制.
- (id)object { id obj = [[NSObject alloc] init]; /* - At this moment, this method has ownership of the object. */ [obj autorelease]; /* - The object exists, and you don’t have ownership of it. */ return obj; }
autorelease
通过autorelease将对象注册到 最近的autoReleasePool中,当pool调用drain
时, 该对象的release被调用.
不要释放, 非你持有的对象
app crash
id obj = [[NSObject alloc] init]; [obj release]; [obj release];
id obj1 = [obj0 object]; [obj1 release];
GNUstep — The alloc Method
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); }
动态分配地址, 并将第一个字节, 转换为引用计数.
GNUstep — malloc && calloc
malloc 分配的空间没有初始化为0, calloc分配的空间初始化为0; calloc可以分配多个
GNUstep — The retain Method
The alloc method returns a memory block filled with zero containing a struct obj_layout header, which has a variable “retained” to store the number of references. This number is called the reference count
id obj = [[NSObject alloc] init]; NSLog(@"retainCount=%d", [obj retainCount]); //1
- (NSUInteger) retainCount { return NSExtraRefCount(self) + 1; } inline NSUInteger NSExtraRefCount(id anObject){ return ((struct obj_layout *)anObject)[-1].retained; }
- (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++; }
GNUstep — The release Method
- (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; } }
GNUstep — The dealloc Method
- (void) dealloc NSDeallocateObject (self); } inline void NSDeallocateObject(id anObject) { struct obj_layout *o = &((struct obj_layout *)anObject)[-1]; free(o); }
GNUstep — 总结
1. All Objective-C objects have an integer value called the reference count.
2. The reference count is incremented by one when one of alloc/new/copy/mutableCopy or retain is called.
3. It is decremented by one when release is called.
4. Dealloc is called when the integer counter becomes zero.
Apple’s Implementation
-retainCount __CFDoExternRefOperation CFBasicHashGetCountOfKey -retain __CFDoExternRefOperation CFBasicHashAddValue -release __CFDoExternRefOperation CFBasicHashRemoveValue
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; } }
在GUNstep的实现中, 引用计数存放在每个obj的header部分, 而Apple的实现, 将所有的对象的引用计数存放在一个HashTable中,
GUNstep实现的好处:
- 更少的代码
- 很容易控制生命周期, 因为计数, 本身包含在每个对象中
Apple实现的好处:
- 每个对象不必有header部分, 从而不需要考虑对齐的问题
- 计数统一管理, 每个对象的计数都可以访问到, 便于系统批量处理.
- 当每个对象的内存出问题的时候, 可以通过hashTable来定位到该对象
Autorelease
Automatic Variables
当一个自动变量, 超出其作用域时, 会自动释放.
{ int a; }
With autorelease, you can use objects in the same manner as automatic variables, meaning that when execution leaves a code block, the “release” method is called on the object automatically. You can control the block itself as well.
The following steps
- Create an NSAutoreleasePool object.
- Call “autorelease” to allocated objects.
- Discard the NSAutoreleasePool object
1 2 3 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; id obj = [[NSObject alloc] init]; [obj autorelease]; [pool drain]; |
In the Cocoa Framework, NSAutoreleasePool objects are created, owned, or disposed of all over the place, such as NSRunLoop, which is the main loop of the application
But when there are too many autoreleased objects, application memory becomes short (Figure 1–14). It happens because the objects still exist until the NSAutoreleasePool object is discarded. A typical example of this is loading and resizing many images. Many autoreleased objects, such as NSData objects for reading files, UImage objects for the data, and resized images exist at the same time.
当有太多autorelease对象时, 程序的可用内存会急剧减少. 因为这些对象会一直存在, 直到pool被结束时.
典型应用场景: 加载或调整大量图片的时候.
|