- 说到内存分区,这里的内存指的就是RAM(random access memory)。
- 内存分为五个区:栈区(系统管理的地方)、堆区(程序员控制的地方)、静态区(全局区)、常量区、代码区
五大分区
栈区
栈是由编译器自动分配释放来管理内存。用户存放程序临时创建的变量、存放函数的参数值、局部变量等。由于栈的先进后出特点,所以特别适合用来做保存/恢复现场的操作。从这个吧意义上,我们可以把栈看做一个临时寄存、交换的内存区。
栈区(stack): 是一段连续的内存区域,从高地址向低地址存储,遵循先进后出(FILO)原则。 一般在运行时进行分配,内存空间由系统管理,变量过了作用域范围后内存便会自动释放。参数、函数、局部变量都放在栈区。参数入栈是从前往后入栈;而结构体入栈是从后往前入栈
- 快速高效,但是有限制,数据不灵活。[先进后出]
- 栈空间分配:静态分配和动态分配两种。静态分配是编译器完成的,比如自动变量(
auto )的分配;动态分配由alloca 函数完成。 - 栈的动态分配无需释放(是自动的),也就没有释放函数。
- 为可移植的程序起见,栈的动态分配操作是不被鼓励的!
堆区
堆区(heap): 由程序员分配和释放,如果程序员不释放,程序结束时,可能会由操作系统回收 ,比如变量通过new 、alloc 、malloc 、realloc 分配的内存块就存放在堆区。
堆向高地址扩展的数据结构,是不连续的内存区域。 程序员负责在何时释放内存,在ARC程序中,计数器为0的时候,在当次的runloop 结束后,释放掉内存。堆中的所有东西都是匿名的,这样不能按名字访问,而只能通过指针访问。 对于堆来讲,频繁的new /delete 势必会造成内存空间的不连续性,从而造成大量的碎片 ,使程序效率降低。
- 灵活方便,数据适应面广泛,但是效率有一定降低。[顺序随意]
- 堆是函数库内部数据结构,不一定唯一。
- 不同堆分配的内存无法互相操作。
- 堆空间的分配总是动态的
- 虽然程序结束时所有的数据空间都会被释放回系统,但是精确的申请内存,释放内存匹配是良好程序的基本要素。
常量区
文字常量区: 存放常量字符串,程序结束后由系统释放
- 该区是编译时分配的内存空间,在程序运行过程中,此内存中的数据一直存在,程序结束后由系统释放。
- 存放常量:整型、字符型、浮点、字符串等。
静态区
全局区(静态区) (static): 全局变量和静态变量的存储是放在一起的,初始化的全局变量和静态变量存放在一块区域,未初始化的全局变量和静态变量在相邻的另一块区域,程序结束后由系统释放。
注意: 全局区又可分为未初始化全局区(BSS段)和初始化全局区(DATA段)。
举例:
int a ;未初始化的;.bss int a = 10 ;已初始化的。.data
代码区
程序代码区: 用来存放函数的二进制代码。
- 它是可执行程序在内存中的镜像。
- 代码段需要防止在运行时被非法修改,所以只允许读取操作,而不允许写入操作。
如何查看一个对象在堆区 / 栈区
- 你初始化方法以
new, alloc, retain,copy 开头都是在堆区,也包括被引用计数管理的对象。常量这些就会在栈区。 简单一点,除去 NSString *aString = @"aaa" 这种编译时会转换为常量其它的 Objective-C 对象,理论上来说,都是在堆区。此外,block 也是个例外,具体的可以去了解内存管理相关的知识点。 - 如果是在方法执行过程当中,定义在本地的原生类型(或者说值类型)。那么肯定它是在栈上。当函数执行结束时直接销毁。而其它的引用类型(或者oc中的
interface )都是在堆上创建的,由ARC负责清理 - 一般情况下你可以打印出地址,判断他是在堆还是栈内存中,栈是高地址往下,堆是低地址往上,一般看到
0x7fff.... 这种的肯定是是在栈中的,要注意一点的是TEXT 段,像NSString 这种基本放在TEXT 段中,这种地址比堆地址更低,也很好区分;你可以去看一下内存是怎么划分的;
注意
- 当一个 app 启动后,代码区、常量区、全局区大小就已经固定,因此指向这些区的指针不会产生崩溃性的错误。而堆区和栈区是时时刻刻变化的(堆的创建销毁,栈的弹入弹出),所以当使用一个指针指向这个区里面的内存时,一定要注意内存是否已经被释放,否则会产生程序崩溃(也即是野指针报错)
- 在 iOS 中,堆区的内存是应用程序共享的,堆中的内存分配是系统负责的
|