内存管理
内存管理,内存资源非常有限,为了合理的分配内存资源所以堆内存进行管理
常见问题: 1> 未初始化,导致报错 2> 越界 导致崩溃 3> 未及时释放 导致内存泄露
1> 内存中的五大区域:
栈: 存储局部变量,当局部变量的作用域执行完毕之后,这个局部变量就会被系统立即回收
堆: 由 C 函数申请的空间,
BSS段: 为初始化的全局变量/静态变量,一旦初始化就回收,并转存到数据段
数据段: 已经被初始化的全局变量/静态变量,直到程序结束的时候才会被回收
代码段: 代码,程序结束的时候,系统会自动回收存储在代码段中的数据
栈,BSS段,数据段,代码段存储在他们中的数据的回收,是由系统自动完成的
存储在堆中的对象系统不会自动回收,直到系统结束的时候才会被回收
2>内存管理的本质是:
当对象发送一条 retain 消息的时候,对象的引用计数器加1,当对象发送一次 release 消息时,引用计数器减1,当引用计数器变为0的时候,对象就会被系统立即回收,这时候会自动调用对象的 delloc 方法
重写 delloc 方法必须调用父类的 delloc 方法,并且要放在最后一句代码
在buildSetting 里面搜索 Automatic reference 设置为 NO 就可以找到关闭 ARC 启用 MRC
3> 内存管理的分类:
1) MRC: manual Reference Counting 手动引用计数
每当多一个人引用对象的时候要求我们手动发送 retain 消息使引用计数器加1,当少1个人引用的时候手动发送 release 消息,是引用计数器减1
2)ARC:(2011 年之后 iOS5 之后推出, xcode7 开始就默认使用 ARC模式) Automatic Reference Counting自动引用计数
4> 内存管理的原则(在 ARC 模式下 retain release delloc 方法无法使用)
1) 有对象创建就要匹配一个 release
2) retain 的次数和 release 次数要一致
3) 谁用谁 retain 谁不用谁 release
4) 多一个人使用就发送一条 retain 消息,少一个人使用就发送一条 release 消息
野指针和僵尸对象
C 语言中的野指针: 定义一个变量,没有初始化,该指针变量的值是一个垃圾值,指向一块随机的空间
OC 语言中野指针: 指针对象指向的空间已经被回收了
内存回收
申请一个变量实际上是向系统申请指定字节的空间,这些空间系统就不会分配给其他对象
当变量被回收的时候,代表所占用的字节空间
对象回收本质: 指对象占用的空间可以分配给别人,当对象占用的空间没有被分配之前对象数据还在
僵尸对象: 一个已经被释放的对象,但是这个对象所占的空间还没有分配给其他对象
我们通过野指针去访问将是对象的时候,有可能有问题有可能没问题
当僵尸对象占用的空间没有被其他对象使用的时候可以,当已经分配给其他对象的时候是不可以的
我们认为只要对象成为了僵尸对象,无论如何都不允许访问了,,我们希望如果被访问的对象时僵尸对象的时候,会报错这时候
我们可以把检测僵尸对象的机制打开(Target -> edit Scheme -> run -> Dianostics -> 选中 Zombie Objects)
但是当打开检测僵尸对象,那么没访问一个对象都会先检测这个对象是否是僵尸对象,这样会消耗性能
当一个指针成为野指针以后将该指针的值设置为 nil, 如果通过这个指针去调用对象方法没有任何反应,如果直接访问对象会报错
一个僵尸对象是无法复活的
单个对象的内存管理
内存泄露:指一个对象该回收的时候没有被回收,一直驻留在内存中,直到程序结束
会发生内存泄露的情况:
1) 有对象创建而没有 release
2) retain 的次数和 release 不匹配
3) 在不适当的时候为指针赋值为 nil (比如 计数器不为 0 的时候)
4) 在方法中为传入对象进行不适当的 retain
避免内存泄露:
1) 有对象创建就必须有 release 匹配
2) retain和 release 个数匹配
3) 只有在指针成为野指针的饿时候才赋值为nil
4) 在方法中不要随意为传入的对象 retain
setter 方法的内存管理:
当属性是一个对象的时候,在 setter 方法中现将传进来的对象发送一条 retain 消息,然后再赋值,当当前对象销毁的时候,在 delloc 方法中发送一条 release 消息
只有指针为野指针的时候再置为nil
当我们将闯入的对象属性赋值给当前对象属性的时候有两层含义(1,_car 属性少一个人用, 传入的对象多一个人用,所以应该先将 _car 属性线本指向的对象 release,再将传入的对象 retain)
当给对象的属性多次赋值的时候会发生内存泄露,应该 release 旧的 retain 新的
如果新旧对象是同一个对象这时候也会发生内存泄,所以需要在 setter 方法中加一层判断,新对象的时候 release 旧的 retain 新的,如果是同一个对象就什么都不做
只有属性的对象是 OC 对象的时候,该属性的 setter 方法才需要这么写
Isa:是一个class类型的指针.每个实例对象有个isa的指针,他指向对象的类,而class里也有一个isa的指针,指向元类.元类保存了类方法的列表.当类方法被调用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查找该方法.同时注意的是:元类也是类,它也是对象.元类也有isa指针,它的isa指针最终指向的是一个根元类.根元类的isa指针指向本身,这样形成了一个封闭的内循环.
每一个对象本质上都是一个类的实例.其中类定义了成员变量和成员方法的列表.对象通过对象的isa指针指向类
每一个类本质上都是一个对象,类其实是元类的实例.元类定义了类方法的列表.类通过类的指针指向元类