内存管理
先简单的说一下什么是内存是来干什么的? 内存当然是用来存数据的
内存管理具体管理的东西是什么? 管理的东西也就是说如何将数据存储到内存中 (比如说我们的声明变量就可以将数据存储到内存中)
存储到内存中的数据怎样释放,什么时候释放?
1.内存中的五大区域: 分别是 栈区/堆区/全局区(静态区)/文字常量区/程序代码区
(1)栈区(stack):由编译器自动分配并释放,存放函数的参数值,局部变量等。栈是系统数据结构,对应线程/进程是唯一的。
优点是快速高效,缺点时有限制,数据不灵活 [先进后出]
栈空间分:静态分配和动态分配两种。
静态分配是编译器完成的,比如自动变量(auto)的分配。
动态分配由alloca函数完成。
栈的动态分配无需释放(是自动的),也就没有释放函数。
(2)堆区(heap):由程序员分配和释放,如果程序员不释放,程序结束时,可能会由操作系统回收 ,比如在ios 中 alloc 都是存放在堆中。
堆是函数库内部数据结构,不一定唯一。不同堆分配的内存无法互相操作。堆空间的分配总是动态的虽然程序结束时所有的数据空间都会被释放回系统,但是精确的申请内存,释放内存匹配是良好程序的基本要素。
打个比喻来说:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。
(3)全局区(静态区) (static):全局变量和静态变量的存储是放在一起的,初始化的全局变量和静态变量存放在一块区域,未初始化的全局变量和静态变量在相邻的另一块区域,程序结束后由系统释放。
注意:全局区又可分为未初始化全局区:
.bss
段和初始化全局区:data段。
(4)文字常量区:存放常量字符串,程序结束后由系统释放
(5)程序代码区:存放函数的二进制代码
2.内存管理分类: ARC MRC
(1).什么是 ARC?
ARC 是 iOS 5 引入的内存管理新功能 -- 也就是自动引用计数 。它的工作原理大致是这样:当我们编译源码时,编译器会分析源码中每个对象的生命周期,然后基于这些对象的生命周期,来添加相应的引用计数操作代码。所以,ARC 是工作在编译期的一种技术方案。
这样的好处是:编译之后,ARC 与非 MRC 代码是没有什么差别的,所以二者可以在源码中共存。实际上,你可以通过编译参数 -fno-objc-arc 来关闭部分源代码的 ARC 特性。由于 ARC 能够深度分析每一个对象的生命周期,它能够做到比 MRC 更加高效。
例如在一个函数中,对一个对象刚开始有一个引用计数 +1 的操作,之后又紧接着有一个 -1 的操作,那么编译器就可以把这两个操作都优化掉。
核心思想:
自己生成的对象,自己持有 相反 非自己生成的对象,自己可以持有
自己持有的对象不再需要时,需要对其进行释放 相反 非自己持有的对象无法释放
3.野指针和空指针:
只要一个对象被释放了,我们就称这个对象为 "僵尸对象(不能再使用的对象)"
当一个指针指向一个僵尸对象(不可用内存),我们就称这个指针为野指针
只要给一个野指针发送消息就会报错(EXC_BAD_ACCESS错误)
例:
int main(int argc,const char * argv[]){
@autoreleasepool {
Person *p =[[Person alloc]init]; //执行完引用计数为1
[p release];//执行完引用计数为0,实例对象被释放
[p release];//此时,p就变成了野指针,再给野指针p发送消息就会报错
[p release];
}
return 0;
}
为了避免给野指针发送消息会报错,一般情况下,当一个对象被释放后我们会将这个对象的指针设置为空指针
空指针指的是: 没有指向存储空间的指针(里面存的是nil, 也就是0) 给空指针发消息是没有任何反应的