美文网首页知识点总结
iOS 内存布局&内存管理

iOS 内存布局&内存管理

作者: 飞不越疯人院 | 来源:发表于2019-04-15 10:45 被阅读5次

    1. 内存布局

    • stack(栈区): 方法调用, 地址从高到低;
    • heap(堆区):通过alloc创建的对象和blockcopy都放在这里, 地址从低到高;
    • bss:未初始化的全局变量等;
    • data:已初始化的全局变量等;
    • text:程序中的代码段加载到内存中放在这里;

    2. 内存管理

    系统堆内存的管理不同的场景有不同的管理方案;

    • TaggedPointer:NSNumber之类的对象;
    • NONPointer_ISA:
    • 散列表:复杂度数据结构, 里面有弱引用表和内存计数表;

    里面是SideTables结构; SideTable(哈希表)包含spinlock_t(自旋锁), RefcountMap(引用计数表), weak_table_t(弱引用表)几部分;

    自旋锁:是一个忙等的锁(当锁被占用时会不停的检测当前线程去尝试使用, 不会阻塞线程); 适用于轻量级的访问;
    引用计数表:通过hash表实现;原因是为了提高查找效率(因为插入和查找是通过同一个hash算法进行的, 避免循环遍历);
    弱引用表:通过hash表实现;原因是为了提高查找效率(因为插入和查找是通过同一个hash算法进行的, 避免循环遍历);


    3. MRC和ARC

    • 什么是MRC:手动管理引用计数;相关函数有alloc, retain, release,retainCount,autorelease,dealloc;
    • 什么是ARC:自动管理引用计数;是编译器(LLVM)和runtime协作的结果;禁止调用retain, release,retainCount,dealloc等方法;新增weak, strong等关键词;
    关键词含义:
    • alloc:一系列调用后最终调用的是C中的calloc, alloc后引用计数并没有置为1;
    • retain:经过(sidetables, sidetable)两次hash查找到后对齐引用计数进行+1操作;

    知识点:系统是如何将weak变量添加到弱引用表中的?
    被声明成__weak的对象指针在通过编译后会依次调用objc_initWeak(), storeWeak(), weak_register_no_lock()几个函数;最终在weak_register_no_lock()函数中进行弱引用变量的添加, 添加的位置时通过hash算法进行位置查找的, 如果查找到相应位置已经有了当前对象所对应的弱引用变量数组就把新的弱引用变量添加到数组, 如果没有则重新创建弱引用数组并在第0个位置添加最新的weak指针(数组有四个元素:其余的初始化为nil);

    知识点:当weak修饰的变量在dealloc时置为nil的过程?
    对象被dealloc后, 在dealloc内部实现中经过一系列的调用最终在weak_clear_no_lock()函数中根据当前对象指针查找弱引用表,把当前对象相对应的(数组)弱引用取出遍历置为nil;


    4. 自动释放池

    什么是自动释放池?
    1. 自动释放池是OC提供的一种回收机制,具有延迟释放的特性
    2. 为节点通过双向链表形式组合而成;
      (每一个自动释放池没有单独结构, 它是有若干个autoreleasePoolPage通过双向链表链接而成)
    3. 与线程一一对应(看autoreleasePoolPage的结构);

    使用场景? 例:在for循环中alloc图片数据等内存消耗较大的场景时手动插入@autoreleasePool; 每次for循环结束进行一次内存释放, 防止内存峰值过大;

    编译器会将@autoreleasepool()改写为以下代码
    void *ctx = objc_autoreleasePoolPush();
    {相关代码}
    objc_autoreleasePoolPop(ctx);
    

    AutoreleasePoolPage结构:

    class AutoreleasePoolPage {
        magic_t const magic;
        id *next;//指向栈顶最新被添加进来的autorelease对象的下一个位置
        pthread_t const thread;//指向当前线程
        AutoreleasePoolPage * const parent;
        AutoreleasePoolPage *child;
        uint32_t const depth;
        uint32_t 
      }
    magic用来校验AutoreleasePoolPage结构是否完整;
    next指向第一个可用的地址;
    thread指向当前的线程;
    parent双向链表中指向父指针;
    child双向链表中指向子指针;
    

    相关文章

      网友评论

        本文标题:iOS 内存布局&内存管理

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