1.栈区(stack):
存放函数的参数值、局部变量的值等,由编译器自动分配释放,通常在函数执行结束后就释放了,其操作方式类似数据结构中的栈。栈内存分配运算内置于处理器的指令集,效率很高,但是分配的内存容量有限,比如iOS中栈区的大小是2M。
2.堆区(heap):
就是通过new、malloc、realloc分配的内存块,它们的释放编译器不去管,由我们的应用程序去释放。如果应用程序没有释放掉,操作系统会自动回收。分配方式类似于链表。
3.静态区:
全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后,由系统释放。
4.常量区:
常量存储在这里,不允许修改的,如数字或字符, 程序退出后自动释放 。
5.代码区
存放函数体的二进制代码。
总结:
> 在函数体中定义的自动变量通常是在栈上,
> 用malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上。
> 加了static修饰符后不管在哪里都存放在全局区(静态存储区)。
> 在所有函数体外定义的是全局变量,存储在全局区(静态存储区)。
> 在所有函数体外定义的static全局变量存储在全局区(静态存储区)。
> 在函数体内定义的static静态变量存储在全局区(静态存储区),表示只在该函数体内有效,但是其生命周期却
变为和 整个程序同生同死。比如:函数中的"adgfdf"这样的字符串存放在常量区。
举例:
一个网上经典的例子:int a = 0; 全局初始化区
char *p1; 全局未初始化区main(){
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20); 分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); 123456放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
NSString * string = @"你好" 你好"在常量区,string在栈上。
}
栈区和堆区的区别主要为以下几点:
1.对于栈来说,内存管理由编译器自动分配释放;对于堆来说,释放工作由程序员控制。
2.栈的空间大小(2M)比堆小许多。
3.栈内存的更新速度要快于堆内存,因为局部变量的生命周期很短,所以分配效率比堆高。
4.栈中存储的变量出了作用域就会被释放,而堆由于是由程序员进行控制释放的(ARC下堆内存存放的实体会被垃圾回收机制不定时的回收),变量的生命周期可以延长。
栈对象严格的定义了生命周期也是其主要的缺点,栈对象的生命周期不适于Objective-C的引用计数内存管理方法。在objective-c中只支持一个类型对象:blocks。
关于在block中的对象的生命周期问题。出现这问题的原因是,block是新的对象,当你使用block时候,如果你想对其保持引用,你需要对其进行copy操作,(从栈上copy到堆中,并返回一个指向他的指针),而不是对其进行retain操作。这就是为什么申明一个block要用copy的原因。
扩展:
1.申请释放方式
在申请内存和释放内存方式方面,堆和栈有着很大的不同,先来谈谈栈是如何实现的吧。栈是编译器自动申请的,例如在主函数里面,要声明一个int变量a,那么编译器就自动开辟一块内存存放变量a。而堆则不相同,是由程序员手动申请的,只要程序员感觉程序此处需要用到多大的内存空间,那么就使用malloc或者new来申请固定大小的内存使用。栈的空间在程序结束的时候由系统或者编译器自动释放,而堆则在程序结束前由程序员手动使用delete释放,或者忘记手动释放,由系统在程序结束的时候自动回收。
2.申请后系统的相应
栈,只要栈剩余的空间大小比申请的空间小,系统就自动为其分配空间,否则就会报错说明栈空间溢出。
堆,首先要知道操作系统中有一个存放空闲存储块的链表,当程序员申请空间的时候,系统就会遍历整个链表,找到第一个比申请空间大的空闲块节点,系统会将该空闲块从空闲链表中删除,分配给程序,同时系统会记录这个空闲块的首地址和申请的大小,当程序员使用delete释放该空间的时候能够找到该存储区。另外,申请的空间不一定与找到的空闲块大小相同,多出来剩余的空闲区会被系统重新添加到空闲链表中。
3.申请的限制
栈,是一种向低地址扩展的数据结构,并且是连续的存储空间,所以栈顶和栈的最大容量是固定的,在windows下,栈的最大容量是2m或者是1m,是在编译的时候就已经确定的,当申请空间大于栈的剩余空间的时候,就会报错说明overflow,所以栈能够申请的空间是比较有限的。
堆,是一种向高地址扩展的数据结构,并且是不连续的,因为系统采用的是链表的方式存放空闲存储块,当然是不连续的,链表的遍历方向是由低向高的,所以堆能够申请的空间的大小其实等同于整个系统的虚拟内存,只要还有内存空间,那么堆就能够不受限制的申请空间,这种方式比较灵活,申请空间也较大。
4.申请效率的比较
栈,因为栈空间的申请是由系统自动完成的,所以速度快,但是不受程序员控制。
堆,空间的申请是由malloc或new来完成的,实现起来较慢,能够产生碎片,但是使用起来方便。
5.存放内容
栈,栈存放的内容,一般来说是函数地址和相关参数。当主函数要调用一个函数的时候,要对当前断点进行保存,需要使用栈来实现,首先入栈的是主函数下一条语句的地址,然后是调用函数的参数,一般情况下是按照从右向左的顺序入栈,之后是调用函数的局部变量,注意静态变量是存放在全局内存区,是不入栈的;出栈的顺序正好相反,最终栈顶指向主函数下一条语句的地址,主程序又从该地址开始执行。
堆,一般情况堆顶使用一个字节的空间来存放堆的大小,而堆中具体存放内容是由程序员来完成的。