美文网首页
内存管理相关

内存管理相关

作者: 细雨菲菲v | 来源:发表于2018-07-16 20:41 被阅读3次

    1.内存布局

    截图1.png
    • stack: 方法调用
    • heap: 通过alloc等分配的对象
    • bss: 未初始化的全局变量
    • data: 已初始化的全局变量
    • text:程序代码

    2.内存管理方案

    • TaggedPointer(小对象,如NSNumber)
    • NONPOINTER_ISA(64位架构下,iOS应用程序,)
    • 散列表
      (1) NONPOINTER_ISA
      arm64架构
      截图2.png

      (2)散列表
      SideTables()结构
      截图4.png
      截图5.png
      思考:为什么不是一个SideTable?
      截图6.png
      为了解决效率问题引入分离锁
      截图7.png
      思考:怎样实现快速分流?
      SideTables的本质是一张Hash表
      截图8.png
      Hash查找
      截图9.png

    3.数据结构

    (1)自旋锁(Spinlock_t)

    Spinlock_t是"忙等"的锁,适用于轻量访问。

    (2)RefcountMap
    截图10.png
    size_t
    截图11.png
    (3) 弱引用表
    截图12.png

    4.MRC&ARC相关

    (1)MRC

    手动引用计数


    截图13.png
    (2) ARC

    自动引用计数

    • ARC是LLVMRuntime协作的结果,
    • ARC中禁止调用`retain/release/retainCount/dealloc
    • ARC中新增weakstrong属性关键字

    5.引用计数管理

    (1)实现原理分析
    • alloc
    • retain
    • release
    • retainCount
    • dealloc
      allloc实现
      经过一系列调用,最终调用了C函数calloc,此时并没有设置引用计数为1。
      retain实现
      截图14.png
      release实现
      截图15.png
      retainCount实现
      截图16.png
      dealloc实现
      截图17.png
      object_dispose()实现
      截图18.png
      objc_destructInstance()实现
      截图19.png
      clearDeallocating()实现
      截图20.png

    6.弱引用管理

    截图21.png
    截图22.png

    7.自动释放池

    • 是以栈为节点通过双向链表的形式组合而成。
    • 是和线程一一对应的

    编译器会将@autoreleasepool{}改写为:

    void * cox = objc_autoreleasePoolPush();
    {}中代码
    objc_autoreleasePoolPop(ctx);

    objc_autoreleasePoolPush

    截图23.png

    objc_autoreleasePoolPop

    截图24.png
    一次pop实际上相当于一次批量的pop操作

    双向列表

    截图25.png

    截图26.png

    AutoreleasePoolPage

    截图27.png
    截图28.png

    AutoreleasePoolPage::push

    截图29.png

    [obj autorelease]

    截图30.png

    AutoreleasePoolPage::pop

    • 根据传入的哨兵对象找到对应的位置
    • 给上次push操作之后添加的对象依次发送release消息
    • 回退next指针到正确的位置

    8.循环引用

    • 自循环引用
    • 相互循环引用
    • 多循环引用
    (1) 自循环引用
    截图31.png
    (2) 相互循环引用
    截图32.png
    (3) 多循环引用
    截图33.png
    (4) 考点
    • 代理
    • Block
    • NSTimer
    • 大环引用

    思考:如何破除循环引用?
    (a)避免产生循环引用
    (b)在合适的时机手动断环
    具体的解决方案有哪些?
    __weak
    __block
    __unsafe_unretained

    __weak破解

    截图34.png
    __block破解
    注意:
    • MRC下,__block修饰对象不会增加其引用计数,避免了循环引用
    • ARC下,__block修饰对象会被强引用,无法避免循环引用,需要手动解环

    __unsafe_unretained破解

    • 修饰对象不会增加其引用计数,避免了循环引用
    • 如果被修饰对象在某一时机被释放,会产生悬垂指针!
    (5)循环引用示例
    • NSTimer的使用示例
      截图35.png
      36.png
      解决方案
      37.png
      在NSTimer和对象之间添加一个中间对象,NSTimer对中间对象实行一个强引用,同时中间对象分别对NSTimer 和对象实行一个弱引用,对于一个重复的定时器而言,当当前页面退出之后,页面释放了对广告栏的强引用,当下次定时器的回调时间回来之后,可以判断广告栏是否被释放掉,如果被释放掉了,在定时器的回调中将定时器进行valite和置为nil
    #import <Foundation/Foundation.h>
    @interface NSTimer (WeakTimer)
    + (NSTimer *)scheduledWeakTimerWithTimeInterval:(NSTimeInterval)interval
                                             target:(id)aTarget
                                           selector:(SEL)aSelector
                                           userInfo:(id)userInfo
                                            repeats:(BOOL)yesOrNo;
    @end
    
    #import "NSTimer+WeakTimer.h"
    
    @interface TimerWeakObject:NSObject
    
    @property (nonatomic,weak)id target;
    
    @property (nonatomic,assign)SEL selector;
    
    @property (nonatomic,weak)NSTimer *timer;
    
    - (void)fire:(NSTimer *)timer;
    
    
    @end
    
    @implementation TimerWeakObject
    
    - (void)fire:(NSTimer *)timer{
        if (self.target) {
            if ([self.target respondsToSelector:self.selector]) {
                [self.target performSelector:self.selector withObject:timer.userInfo];
            }
        } else {
            [self.timer invalidate];
        }
        
    }
    @end
    
    @implementation NSTimer (WeakTimer)
    + (NSTimer *)scheduledWeakTimerWithTimeInterval:(NSTimeInterval)interval
                                             target:(id)aTarget
                                           selector:(SEL)aSelector
                                           userInfo:(id)userInfo
                                            repeats:(BOOL)yesOrNo{
        TimerWeakObject *object = [[TimerWeakObject alloc] init];
        object.target = aTarget;
        object.selector = aSelector;
        object.timer = [NSTimer scheduledWeakTimerWithTimeInterval:interval
                                                            target:aTarget
                                                          selector:aSelector
                                                          userInfo:userInfo
                                                           repeats:yesOrNo];
        return object.timer;
    }
    @end
    

    9.问题

    (1) 什么是ARC ?

    arc是由llvm编译器和runtime共同协作来为我们实现自动引用计数进行管理

    (2) 为什么weak指针指向的对象在废弃之后会被自动置为nil?

    当对象被废弃之后,dealloc方法内部实现中会调用清除弱引用的方法,在清除弱引用的方法中,会通过哈希算法查找被废弃对象在弱引用表中的位置,提取它所对应的弱引用指针一个列表数组,进行for循环遍历把每一个弱引用指针置为nil

    (3) 苹果是如何实现AutoreleasePool的?

    AutoreleasePool是以栈为节点,由双向链表的形式,来合成的数据结构。

    (4) 什么是循环引用?你遇到过哪些循环引用,是怎么解决的?

    相关文章

      网友评论

          本文标题:内存管理相关

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