【iOS】-- 内存五大分区
- 内存五大分区
- 1.栈区
- 优点:
- 2.堆区
- 优点:
- 3.全局区
- 4.常量区
- 5.代码区
- 验证
- static、extern、const关键字比较
- 1.static关键字
- static关键字的作用:
- 全局静态变量
- 局部静态变量
- 2.extern关键字
- 对内的全局变量
- 对外的全局变量
- 3.const关键字
内存五大分区
内存五大分区:
栈区(系统管理的地方),堆区(程序员管理的地方),常量区,全局区(静态区),代码区。
1.栈区
栈区(stack): 是一段连续的内存区域,从高地址向低地址存储,遵循先进后出(FILO)原则。 一般在运行时进行分配,内存空间由系统管理,变量过了作用域范围后内存便会自动释放。参数、函数、局部变量都放在栈区。参数入栈是从前往后入栈;而结构体入栈是从后往前入栈。
优点:
- 栈是系统数据结构,对应线程/进程是唯一的。
- 快速高效,缺点是有限制,数据不灵活。[先进后出]
- 栈空间分静态分配和动态分配两种。
- 静态分配是编译器完成的,比如自动变量(auto)的分配。
- 动态分配由alloc函数完成。
- 栈的动态分配无需释放(是自动的),也就没有释放函数。
下面来看一个例子:
NSObject *obj = [NSObject new];
obj是一个指针变量,不是一个对象,存储在栈区,真正的创建对象,new做的事情有四步:
- 在堆内存中申请一块合适大小的空间。
- 在申请的这块空间中根据类的模板创建对象。
- 初始化对象的属性,为对象的属性赋默认值:
- 如果属性的类型是基本数据类型,就赋值为0。
- C指针类型NULL。
- OC指针类型 nil。
- 返回这个对象在堆空间的地址。
将这个地址返回赋值给obj指针,该指针指向了堆空间中的NSObject对象。
2.堆区
堆区(heap): 由程序员分配和释放,如果程序员不释放,程序结束时,可能会由操作系统回收 ,比如变量通过new、alloc、malloc、realloc分配的内存块就存放在堆区。
堆向高地址扩展的数据结构,是不连续的内存区域。 程序员负责在何时释放内存,在ARC程序中,计数器为0的时候,在当次的runloop结束后,释放掉内存。堆中的所有东西都是匿名的,这样不能按名字访问,而只能通过指针访问。
对于堆来讲,频繁的new/delete势必会造成内存空间的不连续性,从而造成大量的碎片 ,使程序效率降低。
优点:
- 灵活方便,数据适应面广泛,但是效率有一定降低。
- 堆是函数库内部数据结构,不一定唯一。
- 不同堆分配的内存无法互相操作。
- 堆空间的分配总是动态的。
3.全局区
全局区(静态区) (static): 全局变量和静态变量的存储是放在一起的,初始化的全局变量和静态变量存放在一块区域,未初始化的全局变量和静态变量在相邻的另一块区域,程序结束后由系统释放。
全局区又可分为未初始化全局区(BSS段)和初始化全局区(DATA段)。
//举例int a; //未初始化的 .bssint a = 10; //初始化的 .data
4.常量区
文字常量区: 存放常量字符串,程序结束后由系统释放
该区是编译时分配的内存空间,在程序运行过程中,此内存中的数据一直存在,程序结束后由系统释放。
存放常量:整型、字符型、浮点、字符串等。
5.代码区
程序代码区: 用来存放函数的二进制代码。
代码段需要防止在运行时被非法修改,所以只允许读取操作,而不允许写入操作。
验证
运行下面一段代码,看看变量在内存中是如何分配
- (void)test{NSInteger i = 123;NSLog(@"i的内存地址:%p", &i);NSString *string = @"CJL";NSLog(@"string的内存地址:%p", string);NSLog(@"&string的内存地址:%p", &string);NSObject *obj = [[NSObject alloc] init];NSLog(@"obj的内存地址:%p", obj);NSLog(@"&obj的内存地址:%p", &obj);
}
运行结果如下:
- 对于局部变量i,从地址可以看出是0x7开头,所以i存放在栈区
- 对于字符串对象string,分别打印了string的对象地址 和 string对象的指针地址
- string的对象地址是以0x1开头,说明是存放在常量区
- string对象的指针地址是以0x7开头,说明是存放在栈区
- 对于alloc创建的对象obj,分别打印了obj的对象地址 和 obj对象的指针地址(可以参考前文的汇总图)
- obj的对象地址是以0x6开头,说明是存放在堆区
- obj对象的指针地址是以0x7开头,说明是存放在栈区。
static、extern、const关键字比较
1.static关键字
static关键字的作用:
- 可以修饰局部变量,将局部变量存储到静态存储区。
- 可以修饰全局变量,限定全局变量只能在当前源文件中访问。
- 可以修饰函数,限定函数只能在当前源文件中调用。
全局静态变量
优点:无论是类方法还是实例方法都可以访问和修改全局静态变量,外部方法无法调用,供所用对象调用。
缺点:存在生命周期长,直到程序结束。
局部静态变量
优点:定义后只保存一份值,每次调用的时候,没有重新创建,节省空间,只能在该局部代码中使用。
缺点:存在生命周期长,直到程序结束,只能在该局部代码中使用。
2.extern关键字
全局变量分为两种:
对内的全局变量
优点:无论是类方法还是实例方法都可以访问和修改全局静态变量,外部方法无法调用,总所有对象使用
缺点:存在生命周期长,直到程序结束。
对外的全局变量
优点:除了该类,其他文件也可以访问该变量。
缺点:存在的生命周期长,从定义直到程序结束。并且外部可以修改其值,出现错误不容易定位。
全局静态变量与全局变量 其实本质上是没有区别的,只是存在修饰区别,一个static让其只能内部使用,一个extern让其可以外部使用。
3.const关键字
不同于变量,常量的值是固定不可变的,一般用于只读值。
优点:只可以读取值,不能修改。一般用于接口或者文字显示这种固定值。添加extern可以对外全局常量,任意位置都可以访问。
缺点:存在的生命周期长,从定义直到程序结束。需要在.h .m中分别定义代码较多。