心辰·Dev

OC 内存管理技巧分析

引用计数式内存管理的思考方式

  • 自己生成的对象,自己持有。
  • 非自己生成的对象,自己也能持有。
  • 不再需要自己持有的对象时释放。
  • 非自己持有的对象无法释放。
对象操作 Objective-C 方法 引用计数值
生成并持有对象 alloc/new/copy/mutableCopy 等方法 +1
持有对象 retain 方法 +1
释放对象 release 方法 -1
废弃对象 dealloc 方法 -1(归零)

引用计数式内存管理的实现方式

NSObject 类的 alloc 方法执行时所调用的方法和函数有:

  • +alloc
  • +allocWithZone:
  • class_createInstance
  • calloc

retainCount 方法执行时所调用的方法和函数有:

  • -retainCount
  • __CFDoExternRefOperation
  • CFBasicHashGetCountOfKey

retain 方法执行时所调用的方法和函数有:

  • -retain
  • __CFDoExternRefOperation
  • CFBasicHashAddValue

release 方法执行时所调用的方法和函数有:

  • -release
  • __CFDoExternRefOperation
  • CFBasicHashRemoveValue( CFBasicHashRemoveValue 返回 0 时, -release 调用 dealloc )

由上可知内存管理的实现是通过散列表来管理引用计数的。

autorelease 的使用

  • 生成并持有 NSAutoreleasePool 对象;
  • 调用已分配对象的 autorelease 实例方法;
  • 废弃 NSAutoreleasePool 对象。
1
2
3
4
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id obj = [[NSObject alloc] init];
[obj autorelease];
[pool drain];

ARC 内存管理修饰符

  • __strong 修饰符:默认的所有权修饰符,表示对对象的“强引用”。持有强引用的变量在超出其作用域时被废弃。引用的对象会随之释放。
  • __autoreleasing 修饰符:在 ARC 有效时,用 @autoreleasepool 块代替 NSAutoreleasePool 类,用附有 __autoreleasing 修饰符的变量替代 autorelease 方法。
  • __unsafe_unretained 修饰符:在 iOS4 中代替 __weak
  • __weak 修饰符:两个对象互相引用会出现“循环引用”的问题,引起内存泄露,即应当废弃的对象在超出其生存周期后继续存在。弱引用不能持有对象实例。在持有某对象的弱引用时,若该对象被废弃,则此弱引用将自动失效且处于赋 nil 值的状态。使用附有 __weak 修饰符的变量,即是使用注册到 autoreleasepool 中的对象,并且最好先暂时赋值给附有 __strong 修饰符的变量后再使用。

    1
    2
    3
    id __weak o = obj;
    id tmp = o;
    NSLog(@"1 %@", tmp);

ARC 内存管理规则

  • 不能使用 retain / release / retainCount / autorelease
  • 不能使用 NSAllocateObject / NSDeallocateObject
  • 须遵守内存管理的方法命名规则
  • 不能显式调用 dealloc
  • 使用 @autoreleasepool 块代替 NSAutoreleasePool
  • 不能使用 NSZone
  • 对象型变量不能作为 C 语言结构体的成员
  • 显式转换 idvoid *