美文网首页
内存管理/引用计数 - autorelease实现

内存管理/引用计数 - autorelease实现

作者: 关灯侠 | 来源:发表于2018-09-02 18:17 被阅读9次

所有内容引用自《Objective-C 高级编程 iOS与OS X多线程和内存管理》,加入了自己的部分理解。

本节小结,点小1跳到底部[1]
第一节、思考方式
第二节、alloc/retain/release/dealloc实现


autorelease就是自动释放。可类比C的局部变量,超出作用域就会被废弃。

autorelease具体使用如下:
1、生成并持有NSAutoreleasePool对象
2、已分配对象调用autorelease方法
3、废弃NSAutoreleasePool对象

NSAutoreleasePool对象的生命周期相当于C局部变量的作用域。对于所有调用过autorelease的对象,在废弃NSAutoreleasePool对象时,都会调用release

一般情况下,程序主循环NSRunLoop或其他程序可运行的地方,对NSAutoreleasePool对象生成、持有和废弃处理。

只有在大量产生autorelease对象,而NSAutoreleasePool对象还没废弃,对象不能释放,造成内存不足的现象。比如读入大量图像的同时改变尺寸,就有必要自己管理NSAutoreleasePool对象。


GNUstep实现

1、autorelease实现

- (id)autorelease{
    [NSAutoreleasePool  addObject:self];
}

可以看出,就是调用了一个addObject类方法。

为了提高调用效率,使用IMP Caching

// 初始化时,把类名、方法名和函数指针都缓存起来
id autorelease_class = [NSAutoreleasePool class];
SEL  autorelease_sel = @selector(addObject:);
IMP autorelease_imp = [autorelease_class  methodForSelector:autorelease_sel];

使用时直接调用

- (id)autorelease{
    (* autorelease_imp)(autorelease_class,autorelease_sel,self);
}

2、NSAutoreleasePool实现
简化实现:

+ (void) addObject:(id)anObj{
    NSAutoreleasePool *pool = 取得正在使用的NSAutoreleasePool对象;
    if (pool != nil){
        [pool addObject:anObj];
    }eles{
         NSLog(@"NSAutoreleasePool 对象非存在状态下调用autorelease");
    }
}

🌰:
pool就为当前正在使用的NSAutoreleasePool对象。

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id obj = [[NSObject alloc] init];
[obj autorelease];

pool废弃的时候,遍历数组中元素,执行release

苹果实现

objc4库的runtime/objc-arr.mm的实现

class AutoreleasePoolPage{
    static inline void *push(){
      // 相当于生成、持有NSAutoreleasePool类对象
    }
    
    static inline void *pop(void *token){
        // 相当于废弃NSAutoreleasePool类对象
        releaseAll();
    }

    static inline id autorelease(id obj){
      // 相当于NSAutoreleasePool类的addObject类方法
      AutoreleasePoolPage *autoreleasePoolPage = 取得正在使用的AutoreleasePoolPage实例;
      autoreleasePoolPage->add(obj);
    }

    id *add(id obj){
      // 将对象追加到内部数组
    }

    void releaseAll(){
        // 调用内部数组中对象的release实例方法
    }
}

// 对外暴露的方法

// 生成、持有AutoreleasePool对象
void *objc_autoreleasePoolPush(void){
    return AutoreleasePoolPage::push();
}
// 废弃AutoreleasePool对象
void objc_autoreleasePoolPop(void *ctxt){
     AutoreleasePoolPage::pop(ctxt);
}
// 添加对象到AutoreleasePool内部数组
id *objc_autorelease(id obj){
    return  AutoreleasePoolPage::autorelease(obj);
}

举个🌰:

// 等同于objc_autoreleasePoolPush()
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id obj = [[NSObject alloc] init];
// 等同于objc_autorelease
[obj autorelease];
// 等同于objc_autoreleasePoolPop
[pool drain];

小结

1、autorelease本质是添加对象到NSAutoreleasePool类的数组中
2、NSAutoreleasePool生命周期结束后,遍历数组元素执行release
3、一般情况在主循环NSRunLoop或其他可运行的地方,自动管理NSAutoreleasePool生成、持有和废弃。
4、Cocoa框架中很多类方法用于返回autorelease对象
5、为提高执行效率,可以使用IMP Caching


  1. 😊假装是锚点的脚注

相关文章

网友评论

      本文标题:内存管理/引用计数 - autorelease实现

      本文链接:https://www.haomeiwen.com/subject/mhkmwftx.html