内存管理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内存管理相关的知识,希望对你有一定的参考价值。

为什么要注意内存管理

无论编写任何程序, 都需要有效和高效地管理资源。内存资源则是重中之重, 都知道如果电脑内存如果不够用, 系统就能会卡, 反应尺寸, 那么手机也是一样的。在OC程序中对象一旦不需要了必须释放资源.
在一个复杂的系统中,可能很难精确地确定从何时起您不再需要某个对象。Cocoa定义了一些有助于使这一抉择变得更加容易的规则 和原则

注意: 这里直说ios的内存不参与Mac的内存, Mac在10.5以后就有垃圾回收机制。 

非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 即可

 

以上是关于内存管理的主要内容,如果未能解决你的问题,请参考以下文章

ION 内存管理

:内存管理 -- 内存管理的概念

Spark内存管理详解(下)——内存管理

RT-Thread--内存管理

内存管理 浅析 内存管理/内存优化技巧

内存管理相关API列表