内存管理
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内存管理相关的知识,希望对你有一定的参考价值。
为什么要注意内存管理
无论编写任何程序, 都需要有效和高效地管理资源。内存资源则是重中之重, 都知道如果电脑内存如果不够用, 系统就能会卡, 反应尺寸, 那么手机也是一样的。在OC程序中对象一旦不需要了必须释放资源.
在一个复杂的系统中,可能很难精确地确定从何时起您不再需要某个对象。Cocoa定义了一些有助于使这一抉择变得更加容易的规则 和原则
非ARC(iOS5之前)
内存管理原则 :
如果使用alloc、new、copy、mutableCopy创建一个对象, 系统会给这个对象的内部引用计数器赋值1, 您也就拥有这个对象的所有权, 不是自己创建的也可以对对象进行retain操作也会拥有这个对象的所有权。注意如果您对对象retain操作, 其内部的引用计数器也会 +1操作
释放对象的所有权: 可以用release, 或者autorelease自动释放一个对象的所有权. 注意: 不一定release之后对象就一定被释放了, 他只是释放对象的所有权, 换句话来说只是将其内部的引用计数器 -1操作, 对象是否被释放要看内部的【引用计数器】为0
autorelease不是马上释放对象, 而是在一个运行循环(runloop)结束之后向所有等待释放的对象发送一条release操作, 详细介绍在后面
对象的所有权(引用计数器):
说简单点就是如果你引用给一个对象就拥有这个对象的所有权, 一个对象可以被N个所有者拥有, 如果有人拥有这个对象, 那么这个对象就一直存在, 如果没有人拥有就会在运行时被释放. Cocoa 制定了一个非常完美的策略来实现对象是否被释放
- 自己使用alloc, new, copy, mutableCopy创建的对象就有对象的所有权, 并且其内部的引用计数器retainCount=1。
- 如果不是自己创建的您可以用retain来获取对象的拥有权, retain之后, 对象其内部的retainCount+1操作
- 如果不使用对象则需要对对象进行release操作, 其内部retainCount-1, 您也可以使用autorelease自动释放对象
下面我们看看具体代码
- 以new为例
如果您在ARC项目中把一个class修改成非ARC状态之后在执行44行的时候会发现跑通了没报错, 而且他的retainCount值也是1, 首先解决这个现象需要在product-> scheme-> Edit scheme -> Diagnostics -> Enable Zombie Objects勾选上, 在运行就会出错了, 那么这里给你详细的解释是:
事实上obj的确已经被dealloc了,保留计数器的值也已经变成0了,其原来占用的内存也已经不可用了,但是原来这块内存中的内容还没有变(标记删除),将会在未来某个不确定的时间上被清理(就是runloop做的事),这就是为什么NSLog输出的obj保留计数器的值仍为1,而如果在此时再加上一个NSLog, 用1个僵尸对象调用一块被释放的坏内存, 于是程序crash
- 不是自己创建的对象
首先定义一个Student创建一个对象叫car
重写 car对象setter方法, 里面判断是否是同一个对象传进来, 如果不同对象需要对其旧对象释放, 新对象retain操作, 这样就拥有对象的所有权
下面是对象的retainCount值, 如果看不太明白自己动手操作一下就明白了.
引用计数器(保留数)
每一个对象内部都有一个retainCount属性, 用来判断有多少个对象拥有它, 如果没有对象拥有它就被释放
- 当对象被创建(retainCount =1) 引用计数器为1
- 当向对象发送retain消息时, 该对象引用计数器会+1
- 当向对象发送release消息时, 该对象引用计数器会-1, 如果发送autorelease 不会立即-1 是在运行时某一时间-1
- 引用计数器为0 就会被释放掉
自动释放(autorelease)
如果向一个对象发送autoreleace消息之后, 不会立即被释放, 对象会被放入自动释放池中, 等待系统会在某一时间点, 对其释放池内部的所有对象进行一次releace操作,
循环引用
项目中经常出现的就是2个对象互相引用, 你引用我, 我引用你, 这样他们内部的引用计数器始终不为0, 一直都被存在, 导致系统最后crash, 用一个图来说明
学生引用车, 车反过来引用学生, 导致2者都不能被释放, 互相咬着, 谁也不放谁
解决办法: 一端用assign, 一段用retain 即可
以上是关于内存管理的主要内容,如果未能解决你的问题,请参考以下文章