zoukankan      html  css  js  c++  java
  • NSMutableArray 的实现原理

    一、普通C语言的数组实现:

    是开辟一段连续的内存空间,缺点:在插入下标为0的元素,会移动其他所有元素。添加,插入,删除同理。
     
     
     
     
     
     
    当数组非常大时,这样很快会成为问题。
     
     

    二、OC的NSMutableArray实现原理:

     
    1、NSMutableArray 是一个类族,【【NSMutableArray new】 class】 打印出来的是 __NSArrayM。
    2、通过class-dump逆向查看__NSArrayM里面的比较重要的成员变量:
          _used   : 计数
          _list      : 缓冲区指针
         _size     : 缓冲区大小
         _offset  : 缓冲区中的数组的第一个元素的索引
     
     
    3、过程 原理,OC数组比C语言里的数组用了稍微复杂一点的环形缓冲区
    环形缓冲区的特点是:在大多数情况下,除非缓冲区满了,否则不需要频繁分配内存。
    并且NSMutableArray做到了如果我们在中间进行插入或者删除,只会移动最少的一边的元素。
    来看一下 增、删、改、查。
    查询:
    以 -(void)objectAtIndex:(NSIteger)index; 为例子
     
    答:
    -(void)objectAtIndex:(NSIteger)index
           {
             NSIteger originalOffset = _offset  + index;
             NSIteger reallOffset = originalOffset - ( _size > originalOffset ? 0 : size );
     
             Return  _list[ reallOffset ];
            }
    分析:分两种情况,需比较 _size 与  _offset  + index的大小
    A: 当 _size >=   _offset  + index 时:
     
     
    B:当 _size <   _offset  + index 时:
     
     
     

    三、证实过程:

    增加:
    由于逆向不出源码,我们用内存地址来证实这个原理
    插入元素代码:
     
    输出:
     
     
    删除:
     
     
    在没有插入55对象是的array打印结构:
     
     
    插入 str5时,打印array对象:
     
     
     
     
    补充:
    x/100xb arr的意思是: 读取100个字节,并以16进制显示
    • 第一个x是memory read的简写(通过help x可以看出来)
    • 第二个x代表16进制
    • b代表字节
     
     
    四、数组扩容
     
    1、初始化给定容量时,系统会开辟对应的容量,在给定容量特别大时,会crash。
     
      总结:

    当输入值小于等于128且为偶数的情况下:

    初始化最终容量 =  输入的容量的值

    初始化最终容量 =  输入的容量的值 + 1

    当输入值大于128且为偶数的情况下:

    初始化最终容量 = 比输入的容量的值 小且最接近的 2的幂 + 64的倍数

    例子:

    129 - >  128 + 64 = 192 

    193 ->   128 + 2* 62 = 256

    257 ->  256 + 64 = 320

    321  ->  256 + 2* 64 = 384

    959 -> 512 + 7* 64 = 960

    如果有兴趣,大家根据现象可以推倒一下程序是怎么写的 ,但并不重要

     
    用new的方式初始化,没加入元素的时候,是还没有分配内存。
     
     
    2、系统扩容:简单记忆:在现有容量 * 1.625(大概)
     
     
     
    3、扩容后删除元素,数组地址有缩容
    A、删除所有元素
    用removeLastObject,所有元素都删除,数组的内存地址还存在,容量为2
    用removeAllObjects,所有元素都删除,数组被销毁
     
     
     
     
    B、逐个删除元素
     
     
    当有9个元素的时候:缩小规律是:10,4,2
    当有100个元素的时候:缩小规律是:110,42,16,6,2
    当有1205个元素的时候:缩小规律是:1600,640,256,98,38,14,6,2
     
    总结:动态数组在删除元素的时候,会对用缩小容量。规则:d = 数组当前容量 / k ( k 为2.5 到 2.7中间的数,大家有兴趣可以自己逆向试试找一下这个数组); 当数组的元素数量 小于等于 d时,会在内存开辟一个大小为d的线性内存,把数组赋值到新地址中,达到节省内存的目的。
    这块有个设计的注意点:扩容和缩容的比例不一样,可以避免临界值的性能问题。不会到达某个值添加一个扩容,删除一个缩小。
     
    注:这块内容网上结识的比较少,是我自己总结,可以大家再一起讨论。
     
     
     
  • 相关阅读:
    R语言:随机抽样(sample函数)
    SNP (Single Nucleotide Polymorphism), SNV ( single nucleotide variants ) , Indel (insertion-deletion) 的区别
    剑指offer五十六之删除链表中重复的结点
    剑指offer五十五之链表中环的入口结点
    剑指offer五十四之字符流中第一个不重复的字符
    剑指offer五十三之表示数值的字符串
    剑指offer五十二之正则表达式匹配
    剑指offer五十一之构建乘积数组
    求游戏晋级花费的宝石的期望
    剑指offer五十一之构建乘积数组
  • 原文地址:https://www.cnblogs.com/miaomiaocat/p/14129539.html
Copyright © 2011-2022 走看看