一、普通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。
 
 
用new的方式初始化,没加入元素的时候,是还没有分配内存。
 
 
2、系统扩容:在现有容量 * 1.625, 0 - 2 - 2 * 1.625  -   2 * 1.625 * 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的线性内存,把数组赋值到新地址中,达到节省内存的目的。
这块有个设计的注意点:扩容和缩容的比例不一样,可以避免临界值的性能问题。不会到达某个值添加一个扩容,删除一个缩小。
 
注:这块内容网上结识的比较少,是我自己总结,可以大家再一起讨论。
 
 
 

NSMutableArray 的实现原理的更多相关文章

  1. NSmutableArray 的实现原理机制

    古老的C数组: 优点:查询速度很快,直接通过下表找到对应的值 缺点:修改.删除数据很慢,需要移动基于所有的其他的元素   插入和删除一个元素,需要移动后面所有的元素 改进的目标:实现快速增加,删除 N ...

  2. Objective-C中block的底层原理

    先出2个考题: 1. 上面打印的是几,captureNum2 出去作用域后是否被销毁?为什么? 同样类型的题目: 问:打印的数字为多少? 有人会回答:mutArray是captureObject方法的 ...

  3. iOS-SDWebimage底层实现原理

    其实有些框架的实现原理,并没有想象中那么难,思想也很简单,主要是更新第三方框架的作者对自己写的代码,进行了多层封装,使代码的可读性降低,也就使得框架看起来比较难.我来实现以下SDWebimage的的曾 ...

  4. IOS热更新-JSPatch实现原理+Patch现场恢复

    关于HotfixPatch 在IOS开发领域,由于Apple严格的审核标准和低效率,IOS应用的发版速度极慢,稍微大型的app发版基本上都在一个月以上,所以代码热更新(HotfixPatch)对于IO ...

  5. JSPatch 实现原理详解

    原文地址https://github.com/bang590/JSPatch/wiki/JSPatch-%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86%E8%AF%A6%E8 ...

  6. iOS开发——多线程篇——快速生成沙盒目录的路径,多图片下载的原理、SDWebImage框架的简单介绍

    一.快速生成沙盒目录的路径 沙盒目录的各个文件夹功能 - Documents - 需要保存由"应用程序本身"产生的文件或者数据,例如:游戏进度.涂鸦软件的绘图 - 目录中的文件会被 ...

  7. NSRunLoop 概述和原理

    NSRunLoop 概述和原理 1.什么是NSRunLoop? 我们会经常看到这样的代码: - (IBAction)start:(id)sender { pageStillLoading = YES; ...

  8. collectionView布局原理及瀑布流布局方式

    一直以来都想研究瀑布流的具体实现方法(起因是因为一则男女程序员应聘的笑话,做程序的朋友应该都知道).最近学习到了瀑布流的实现方法,瀑布流的实现方式有多种,这里应用collectionView来重写其U ...

  9. KVC/KVO原理详解及编程指南

    一.简介 1.KVC简介 2.KVO简介 二.KVC相关技术 1.Key和Key Path 2.点语法和KVC 3.一对多关系(To-Many)中的集合访问器方法 4.键值验证(Key-Value V ...

随机推荐

  1. 《JavaScript高级程序设计》读书笔记 ---继承

    继承是OO 语言中的一个最为人津津乐道的概念.许多OO 语言都支持两种继承方式:接口继承和实现继承.接口继承只继承方法签名,而实现继承则继承实际的方法.如前所述,由于函数没有签名,在ECMAScrip ...

  2. Leetcode 1329. 将矩阵按对角线排序 题解

    首先遍历对角线元素,顺序为: 先从第一列的最后一行到第一行 然后从第一行的第一列到最后一列 遍历的同时记录坐标和数值,对数值进行排序,然后坐标顺序放回. class Solution: def dia ...

  3. 信息收集之——旁站、C段

    旁站的概念 ​旁站指的是同一服务器上的其他网站,很多时候,有些网站可能不是那么容易入侵.那么,可以查看该网站所在的服务器上是否还有其他网站.如果有其他网站的话,可以先拿下其他网站的webshell,然 ...

  4. CorelDRAW:油漆滚轮及LOGO设计

    小马坐在电脑前,看着自己画的油漆滚轮Logo,既生气又无奈.为了这个油漆Logo,小马用了四.五个不同的设计软件,也画了不下10个图案,就没有一个满意的."明天就要交稿了,现在都11点多了, ...

  5. 【PUPPETEER】初探之拖拽操作(五)

    一.知识点 page.mouse elementHandle.boundingBox() ignoreDefaultArgs:['--enable-automation']   waitUntil 二 ...

  6. Python_生成器和迭代器的区别

    迭代器和生成器的区别是什么?这个问题面试的时候经常作为灵魂拷问.今天一起从概念到代码梳理一遍,作为总结和记录. 区别是: 生成器的好处是延迟计算,一次返回一个结果.也就是说,它不会一次生成所有的结果, ...

  7. Docker基础知识及入门

    什么是Docker? Docker是由dotcloud公司使用golang语言进行开发的,基于Linux内核的 cgroup,namespace,以及OverlayFS类的Union FS等技术,对进 ...

  8. hibernate一对多,细节讲解

    1.一对多 1).首先创建两个实体类studeninfo.java跟studentxxb.java 1)studentinfo.java表如图: package model; import java. ...

  9. 训练yolo之前,anchor聚类问题

    前期做数据可视化,发现标签数据存在一些孤立点(噪声点),影响kmeans聚类. 处理方法如下: 使用kmeans迭代10次得到聚类中心 计算所有数据到其聚类中心的欧式距离均值和方差 通过拟合正态分布, ...

  10. 「考试」noip模拟9,11,13

    9.1 辣鸡 可以把答案分成 每个矩形内部连线 和 矩形之间的连线 两部分 前半部分即为\(2(w-1)(h-1)\),后半部分可以模拟求(就是讨论四种相邻的情况) 如果\(n^2\)选择暴力模拟是有 ...