美文网首页
iOS日记5-autoreleasepool和autorelea

iOS日记5-autoreleasepool和autorelea

作者: Mcyboy007 | 来源:发表于2017-02-09 20:20 被阅读0次

    1.autoreleasePool的具体使用

    MRC:
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    id obj = [[NSObject alloc] init];
    [obj autorelease];
    [pool drain];  //调用[obj release] 
    
    ARC和MRC:
    @autoreleasepool {
      id obj = [[NSObject alloc] init];
    }
    

    2.autoreleasepool原理

    1)与NSRunLoop的关系

    每一个线程(包括主线程)都有一个NSAutoreleasePool栈. 当一个新的池子被创建的时候, push进栈. 当池子被释放内存时, pop出栈. 对象调用autorelease方法进入栈顶的池子中. 当线程结束的时候, 它会自动地销毁掉所有跟它有关联的池子.
    在当前的runloop迭代中,系统会加入autoreleasepool的push和pop操作,用于管理对象。

    2)内部实现

    这里涉及到了一个AutoreleasePoolPage类。

    //非完整实现
    struct AutoreleasePoolPage {
      magic_t const magic;
      id *next;
      pthread_ const thread;
      AutoreleasePoolPage *const parent;
      AutoreleasePoolPage *child;
      uint32_t const depth;
      uint32_t hiwat;
    }
    
    • AutoreleasePool并没有单独的结构,而是由若干个AutoreleasePoolPage以双向链表的形式组合而成(分别对应结构中的parent指针和child指针)
    • AutoreleasePool是按线程一一对应的(结构中的thread指针指向当前线程)
    • AutoreleasePoolPage每个对象会开辟4096字节内存(也就是虚拟内存一页的大小),除了上面的实例变量所占空间,剩下的空间全部用来储存autorelease对象的地址
    • 上面的id *next指针作为游标指向栈顶最新add进来的autorelease对象的下一个位置
    • 一个AutoreleasePoolPage的空间被占满时,会新建一个AutoreleasePoolPage对象,连接链表,后来的autorelease对象在新的page加入

    使用@autoreleasepool{ }时,编译器将其改写为:

    void *context = objc_autoreleasePoolPush();  //作为一个记录点,每一次的释放会将2个记录点内的对象都释放,直到完全释放
    //some codes
    objc_autoreleasePoolPop(context);
    

    3.需要手动创建autoreleasepool的时候

    • 1.写的程序不是基于UIFrameWork,例如命令行项目
    • 2.写的循环大量创建临时对象。可以在循环中创建autoreleasepool,在池子中创建对象。这样有助于降低内存峰值
    • 3.创建了一个新的线程,线程开始执行时,需要立刻创建一个autoreleasepool

    4.参考资料

    http://blog.sunnyxx.com/2014/10/15/behind-autorelease/
    http://www.jianshu.com/p/5559bc15490d
    《Objective-C高级编程:ios与OS X多线程和内存管理》

    相关文章

      网友评论

          本文标题:iOS日记5-autoreleasepool和autorelea

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