美文网首页
性能优化-内存管理

性能优化-内存管理

作者: 纳兰沫 | 来源:发表于2020-05-15 18:58 被阅读0次

    内存布局

    内存布局.png
    栈区向下扩展 堆区向上扩展 由于内存有限,如果碰面就会出现堆栈溢出的情况
    在栈区里面因为方法 函数 会形成栈帧
    .bss 又称静态区
    .data又称全局区
    如何找到对象的数值?
    1.先找到在栈区的对象所对应的指针
    2.根据指针找到指针所指向的那个在堆区的对象
    3.在获取对象的具体数值
    

    内存优化的原因

    栈是512kb = 512*1024 字节,由于每个指针所占内存为8个字节,那么栈区大概可以存放512*1024 / 8 = 65536个指针,也就是说
    超过这个数值 会出现内存溢出的情况 因此需要内存优化
    

    全局静态变量要放在.m中,避免不必要的问题
    在方法中尽量使用嵌套(封装方法 函数)来加快读取效率 因为如果变量过多,会导致函数指针更加难别识别 这个方法是空间换时间
    方法和函数的区别
    函数 属于整个文件 可以直接调用 把函数写在类的声明中不会被识别

    //外部函数
    extern void sayHi(){
        printf("sayHi\n");
    }
    //内部函数
    static void sayHello(){
        printf("sayHello");
    }
    

    方法 依赖于类 不能脱离类而存在 只能通过实例对象或者类调用

    @interface Person : NSObject
    @property (nonatomic,copy) NSString *firstName;
    //方法声明
    - (void)run;
    + (void)play;
    @end
    
    @implementation Person
    //方法声明实现
    - (void)run{
        NSLog(@"%s",__func__);
    }
    + (void)play{
        NSLog(@"%s",__func__);
    }
    @end
    

    内存管理方案

    • taggedPointer
      @taggedPointer用于NSNumber NSDate NSString等内容较少的情况 节省内存空间,同时他的读取速度较快是原先的3倍 创建速度是106倍
      @小对象的地址存储的内容包括有本身所代表的值和类型
      taggedPointer编码.png
      taggedPointer解码.png
      普通的值进行编码之后 方便系统识别是否为taggedPointer 如果是taggedPointer 直接返回值 不需要漫长的寻找过程 解码是还原出taggedPointer存储的真正的地址
      得出结论一个值异或2次相同的值之后得到的还是原先的值
      image.png
    原先是直接异或0 现在是另外的值 是加密 不希望暴露出来
    
    image.png
    第一个不崩溃 taggedPointer不经过retain release 直接返回
    第二个崩溃 是多线程不断的retain release造成崩溃 不是小对象
    
    image.png
    image.png
    • NONPOINTER_ISA 非指针型isa
      联合体 位域优化了isa 每一位都代表不同的值
      不同的架构下面 isa是不同的 能够存储更多的空间
    nonpointer:表示是否对 isa 指针开启指针优化 0:纯isa指针,1:不不⽌止是类对象地址,isa 中包含了了类信息、对象的引⽤用计
    has_assoc:关联对象标志位,0没有,1存在
    has_cxx_dtor:该对象是否有 C++ 或者 Objc 的析构器器,如果有析构函数,则需要做析构逻辑, 如果没有,则可以更更快的释放对象
    shiftcls: 存储类指针的值。开启指针优化的情况下,在 arm64 架构中有 33 位⽤用来存储类指针。
    magic:⽤用于调试器器判断当前对象是真的对象还是没有初始化的空间
    weakly_referenced:志对象是否被指向或者曾经指向⼀一个 ARC 的弱变量量,
    没有弱引⽤用的对象可以更更快释放。
    deallocating:标志对象是否正在释放内存
    has_sidetable_rc:当对象引⽤用技术⼤大于 10 时,则需要借⽤用该变量量存储进位
    

    如果自定义实现了retain release allocWithZone 不再调用系统的 而是使用自己的实现的话, 那么isa是不会被优化的

    • 散列表 SideTable
      SideTable 包括自旋锁 引用计数表 弱引用表
      为什么是多张SideTable 不是一张SideTable
    1.如果一个SideTable里面有多个对象 对每个对象进行操作 会造成对SideTable的操作过于频繁 影响性能
    2.由于SideTable里面有自旋锁 如果一个SideTable里面有多个对象 对每个对象进行操作时 都要进行加锁解锁 同时由于自旋锁的
    特性,会造成一直处于忙等状态 违背了自旋锁的操作过于简单的设计原则
    3.分成多个SideTable 会达到分离锁的效果
    

    关于每个对象存放于哪个SideTable 是根据对象 创建的时间以及一些特殊函数等其他来进行划分的

    哈希表

    哈希表是结合了数组+链表
    数组是查询非常快 通过下标来查询 增删复杂
    链表是在数据结构中增删比较有优势
    哈希表是通过下标获取具体的key value
    通过拉链法解决离散冲突

    SideTables里面有很多SideTable
    stripeMap通过array[indexofPOINTER].value获取
    

    相关文章

      网友评论

          本文标题:性能优化-内存管理

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