一、普通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. Python_俄罗斯方块

    网上资料,仅供学习,希望以后自己也能看懂再改进下... """ 俄罗斯方块 author: wolfstar last edited: 2018年1月 "&qu ...

  2. Python pip下载过慢解决方案

    pip是一个python的包安装与管理工具,安装python时候可以选择是否安装,如果安装了pip可以使用命令查看版本 C:\Users\Vincente λ pip -V pip 19.2.3 fr ...

  3. 死磕以太坊源码分析之Kademlia算法

    死磕以太坊源码分析之Kademlia算法 KAD 算法概述 Kademlia是一种点对点分布式哈希表(DHT),它在容易出错的环境中也具有可证明的一致性和性能.使用一种基于异或指标的拓扑结构来路由查询 ...

  4. c# 调用Go 动态库

    [StructLayout(LayoutKind.Sequential)] public struct GoMem { public IntPtr data; public UInt64 len; p ...

  5. java开发两年,连这些多线程知识都还没掌握,你凭什么涨薪!

    并发与并行 并发:两个或者多个事件在同一时间段发生(交替执行) 并行:两个或者多个事件在同一时刻发生(cpu多核.同时执行) 线程与进程 进程:是一个内存中运行的应用程序,有自己独立的内存空间,一个应 ...

  6. 使用思维导图MindManager能否增强记忆?

    学生时代,每当面对冗杂的需要背诵的课业时,有很多人都会发出"这么多内容怎么背啊"."我讨厌死记硬背"."昨天背完今天就忘了"的呐喊.那么,如 ...

  7. js 手机号验证

    1 js 通过正则表达式对手机号进行验证 2 3 var reg = /^1[3|4|5|8][0-9]\d{4,8}$/; 4 var sMobile = document.mobileform.m ...

  8. Calling unknown method: app\modules\mobile\controllers\CompanyController::redirect()

    $this->redirect(['default/error']); Yii::$app->end();上边的代码出现 Calling unknown method: app\modul ...

  9. jmeter简单的压力测试

    Jmeter是一个非常好用的压力测试工具.  Jmeter用来做轻量级的压力测试,非常合适,只需要十几分钟,就能把压力测试需要的脚本写好.相比LR来说操作简单方便,关键是免费,基于JAVA开发,所以需 ...

  10. 网络管理监视很重要!学编程的你知道哪些不错的网络监控工具?2020 最好的Linux网络监控工具分享给你

    以下文章来源于新钛云服 翻译:侯明明 前言 虽然这个清单包含开源的和闭源的产品,但它着重于介绍基于 Linux 的网络监控工具, 少数常用工具只能在 Windows,Pandora 或其他系统上运行, ...