马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
OC语言是C语言的超集,以是先相识C语言的内存模子的内存管剖析有很大资助。C语言的内存模子分为5个区:栈区、堆区、全局/静态区、常量区、代码区
一样平常情况下步调存放在ROM(只读内存,比如硬盘)或Flash中,运行时须要拷到RAM(随机存储器RAM)中实行,RAM会分别存储差异的信息,如下图所示:
RAM(random access memory):运行内存,CPU可以直接访问,读写速率快,但是不能掉电存储。它又分为:
- 动态DRAM,速率慢一点,须要定期的革新(充电),常说的内存条就是指它,代价会稍低一点,手机中的运行内存也是指它
- 静态SRAM,速率快,我们常说的一级缓存,二级缓存就是指它,代价高一点
ROM(read only memory):存储性内存,可以掉电存储,eg:SD卡、Flash(机器磁盘也可以简朴的明白为ROM)。用的多的:NandFlash(空间大,自制),另有NorFlash(直接运行步调,读取速率快)
|_|
由于RAM范例不具备掉电存储本事(即一制止供电数据全没了,重新上电后满是乱码,以是须要初始化),以是app步调一样平常存放于ROM中。RAM的访问速率要远高于ROM,代价也要高
由于RAM不能掉电存储,以是我们的APP步调,刷机包,下载的文件等等,都是在ROM内里存储的
手机内里利用的ROM根本都是NandFlash,CPU是不能直接访问的,而是须要文件体系/驱动步调(嵌入式中的EMC)将其读到RAM里CPU才可以访问
下面先相识一下堆是怎么存放和利用数据的
堆(Heap)是什么
堆是盘算机科学中一类特别的数据布局的统称。在队列中,调治步调反复提取队列中第一个作业并运行,由于现真相况中某些时间较短的任务将等待很长时间才华竣事,大概某些不短小,但具有紧张性的作业,同样应当具有优先权。堆即为办理此类标题计划的一种数据布局
|_|
堆(Heap)又被为优先队列(priority queue)。只管名为优先队列,但堆并不是队列。在堆中,我们不是按照元素进入队列的先后次序取出元素的,而是按照元素的优先级取出元素
这就似乎候机的时间,无论谁先到达候机厅,总是头等舱的搭客先登机,然后是商务舱的搭客,末了是经济舱的搭客。每个搭客都有头等舱、商务舱、经济舱三种个键值(key)中的一个。头等舱->商务舱->经济舱依次享有从高到低的优先级
总的来说,堆是一种数据布局,数据的插入和删除是根据优先级定的,他有几个特性:
- 恣意节点的优先级≥它的子节点
- 每个节点值都≤它的子节点
- 紧张利用是插入和删除最小元素(元素值本身为优先级键值,小元素享有高优先级)
举个例子,就像叠罗汉,体庞大(优先级低、值大)的站在最下面,体重小的站在最上面(优先级高,值小)。 为了让堆稳固,我们每次都让最上面的到场者退出堆,也就是每次取出优先级最高的元素
五大分区
栈区
- 栈是一块连续的内存地区从高地点向低地点举行存储,遵照先辈后出(FILO)原则
- 栈区由利用体系在运行时自动分配,声明的变量过了作用域范围后内存便会自动开释,静态分配由编译器完成(自动变量auto),动态分配由alloc函数完成
- 函数内部界说的局部变量、方法参数(方法中的默认参数:self、_cmd),都存放在栈区
- 优缺点
- 长处:栈是由体系自动分配并开释的,不会产生内存碎片,以是快速高效(栈利用的是一级缓存, 他们通常都是被调用时处于存储空间中,调用完毕立刻开释)
- 缺点:查察官方文档,栈的内存巨细有限定,数据不机动,iOS 主线程栈巨细是1MB,其他线程是512KB,MAC只有8M
- 栈的地点空间在iOS中是以0x7/0x16开头
- - (void)testStack {
- int a = 7777777;
-
- NSLog(@"a == %p, size == %lu", &a, sizeof(a));
- NSLog(@"方法参数self:%p", &self);
- NSLog(@"方法参数cmd:%p", &_cmd);
- }
复制代码 堆区
- 堆是不连续的内存地区从从低地点向高地点举行存储,雷同于链表布局(便于增删,未便于查询),遵照先辈先出(FIFO)原则
- 开发者须要关注变量的生命周期,假如不及时开释,会造成内存走漏,只有等步调竣事时由利用系齐备一接纳
- 存放的是OC中运行时利用alloc、new创建的对象,C/C++中利用malloc、calloc以及realloc分配的空间,须要free开释
- 优缺点
- 长处:得到空间机动,分配内存较大
- 缺点:需手动管理,频仍的new/delete势必会造成内存空间的不连续性,速率慢、容易产生内存碎片(堆则是存放在二级缓存中,生命周期由假造机的垃圾接纳算法来决定,并不是一旦成为孤儿对象就能被接纳)
- 堆的地点空间在iOS中是以0x6开头
- - (void)testHeap {
- NSObject* object1 = [[NSObject alloc] init];
- NSObject* object2 = [[NSObject alloc] init];
- NSLog(@"object1 = %@", object1);
- NSLog(@"object2 = %@", object2);
- }
复制代码 全局/静态区
- 该区是编译时分配的内存空间,在步调运行过程中,此内存中的数据不停存在,全局变量和静态变量的存储是放在一起的,初始化的全局变量和静态变量存放在一块地区,未初始化的全局变量和静态变量在相邻的另一块地区,步调竣事后由体系开释
- 未初始化的全局变量和静态变量,即BSS区(.bss)
- 已初始化的全局变量和静态变量,即数据区(.data)
- 全局区的空间地点在iOS中一样平常以0x1开头
- int bssA;
- static double dataB = 7.0;
- - (void)testExOrSt {
- NSLog(@"bssA == %p", &bssA);
- NSLog(@"dataB == %p", &dataB);
- }
复制代码 常量区(即.rodata)
- 该区是编译时分配的内存空间,在步调运行过程中,此内存中的数据不停存在,步调竣事后由体系开释
- 存放的是整型、字符型、浮点、常量字符串等常量
- 常量只读
代码区(.text)
- 该区是编译时分配的内存空间,在步调运行过程中,此内存中的数据不停存在,步调竣事后由体系开释
- 步调运行时的代码会被编译成二进制,存进内存的代码地区
- 只读,代码段须要防止在运行时被非法修改,以是只答应读取利用,而不答应写入利用
函数栈
函数栈:又称为栈区,在内存中从高地点往底地点分配,与堆区相对。
栈帧:指函数(运行中且未完成)占用的一块独立的连续内存地区
应用中新创建的每个线程都有专用的栈空间,栈可以在线程期间自由利用。而线程中有千千万万的函数调用,这些函数共享进程的这个栈空间。每个函数所利用的栈空间是一个栈帧,全部的栈帧就构成了这个线程完备的栈
函数调用是发生在栈上的,每个函数的干系信息(比方局部变量、调用记载等)都存储在一个栈帧中,每实行一次函数调用,就会天生一个与其干系的栈帧,然后将其栈帧压入函数栈,而当函数实行竣事,则将此函数对应的栈帧出栈并开释掉
以下是ARM的栈帧布局方式:
- main stack frame为调用函数的栈帧
- func1 stack frame为当前函数(被调用者)的栈帧
- 栈底在高地点,栈向下增长。
- FP就是栈基址,它指向函数的栈帧起始地点
- SP则是函数的栈指针,它指向栈顶的位置
- ARM压栈的次序非通例矩(也比力容易被黑客攻破么),依次为当前函数指针PC、返回指针LR、栈指针SP、栈基址FP、传入参数个数及指针、本地变量和临时变量。假如函数准备调用另一个函数,跳转之前临时变量区先要生存另一个函数的参数
- ARM也可以用栈基址和栈指针明白标示栈帧的位置,栈指针SP不停移动,ARM的特点是,两个栈空间内的地点(SP+FP)前面,一定有两个代码地点(PC+LR)明白标示着调用函数位置内的某个地点
堆栈溢出
一样平常情况下应用步调是不须要思量堆和栈的巨细的,但是毕竟上堆和栈都不是无上限的,过多的递归会导致栈溢出,过多的alloc变量会导致堆溢出
以是防备堆栈溢出的方法:
- 制止条理过深的递归调用
- 不要利用过多的局部变量,控制局部变量的巨细
- 制止分配占用空间太大的对象,并及时开释
- 着实不可,得当的景象下调用体系API 修改线程的堆栈巨细
堆和栈的区别和接洽
1. 各自的优缺点?
- 栈:由编译器自动分配并开释,速率较快,不会产生内存碎片。长处是快速高效,缺点时有限定,数据不机动
- 堆:由步调员分配和开释,速率比力慢,而且容易产生内存碎片,不外用起来最方便。长处是机动方便,数据顺应面广泛,但是服从有肯定低沉
2. 申请后的体系怎样相应?
- 栈:存储每一个函数在实行的时间都会向利用体系索要资源,栈区就是函数运行时的内存,栈区中的变量由编译器负责分配和开释,内存随着函数的运行分配,随着函数的竣事而开释,由体系自动完成。只要栈的剩余空间大于所申请空间,体系将为步调提供内存,否则将报非常提示栈溢出。
- 堆:利用体系有一个记载空闲内存地点的链表。当体系收到步调的申请时,会遍历该链表,探求第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给步调。由于找到的堆结点的巨细不肯定恰好便是申请的巨细,体系会自动的将多余的那部门重新放入空闲链表中
3. 申请巨细的限定?
- 栈:栈是向低地点扩展的数据布局,是一块连续的内存的地区。是栈顶的地点和栈的最大容量是体系预先规定好的,栈的巨细是2M(也有的说是1M,总之是一个编译时就确定的常数 ) ,假如申请的空间凌驾栈的剩余空间时,将提示overflow。因此,能从栈得到的空间较小
- 堆:堆是向高地点扩展的数据布局,是不连续的内存地区。这是由于体系是用链表来存储的空闲内存地点的,天然是不连续的,而链表的遍历方向是由低地点向高地点。堆的巨细受限于盘算机体系中有效的假造内存。由此可见,堆得到的空间比力机动,也比力大
图解
|