性能之内存管理

应用中的内存消耗分为:栈大小和堆大小。

栈大小

  • 可被递归调用的最大方法数
  • 一个方法中最多可以使用的变量个数
  • 视图层级中可以嵌入的最大视图深度

堆大小

每个进程的所有线程共享一个堆。一个应用可以使用的堆大小通常远远小于设备的RAM值。

自动释放池块(autoreleasepool)

在一些特殊情况下,需要创建自己的autoreleasepool。
* 当你有一个创建了很多临时对象的循环时
* 当你创建一个线程时

ARC的规则

* 不能实现或调用retain、release、autorelease或retainCount方法
  这一规则不仅针对对象,对选择器同样有效
* 可以实现dealloc方法,但不能调用它包括超类
* 不能调用NSAllocateObject和NSDeallocateObject方法
  应该使用alloc方法创建对象,运行时负责回收对象
* 不能在C语言的结构体内使用对象指针
* 不能在 id 类型和void * 类型之间自动转换。如果需要,必须做显示转换。
* 不能使用NSAutoreleasepool,要替换成autoreleasepool
* 不能使用NSZone内寸区域
* 属性的访问器名称不能以new开头,以确保与MRC的互操作性
* Core Foundation类型需要自己手动管理内存

引用类型

  • 弱引用:不会增加引用计数
  • 强引用:会增加引用计数

变量限定符

  • _strong、 _weak 、_unsafe_unretained、_autoreleasesing
    例子:
    Person* _strong p1 = [[Person alloc] init]// 引用计数为1,并且对象在p1引用期间不会被回收
    Person* _weak p2 = [[Person alloc] init]// 引用计数为0,对象会被立即释放,且p2将被设置为nil
    Person* _unsafe_unretained p3 = [[Person alloc] init]// 引用计数为1,对象会被立即释放,且p3不会被设置为nil
    Person*_autoreleasing p4 = [[Person alloc] init]// 引用计数为1,当方法返回时对象会被立即释放

属性限定符

这个就不在此做解释了,不懂的,百度上有很多教程

僵尸对象

用来捕捉内存错误的调试功能
通常情况下,当引用计数为0时,对象会立即释放,会使得调试困难。开启僵尸对象,那么对象不会立即释放内存,而是标记为僵尸。
NSZombieEnabled是一个环境变量,可以控制Core Foundation的运行时是否将使用僵尸对象
注意:在发布构建时一定要禁用

内存管理规则

* 你拥有所有自己创建的对象,如new、alloc、copy、mutableCopy
* 你可以用MRC中的retain或ARC中的__strong引用来拥有任何对象的持有关系
* 一定不能抛弃原本并不存在持有关系的对象

循环引用

主要出现的场景委托、块、线程与计时器

观察者

  • 键-值观察
    它不会维持观察对象、被观察对象以及上下文对象的强引用。如有必要,你需要自行维护对它们的强引用。
  • 通知中心
    一个对象可以注册为通知中心的观察者,并接收NSNotification对象。它不会对观察者持有强引用。

返回错误

当某个方法接收NSError**参数,并在发生错误时填充错误变量,则必须使用__autoreleasing限定符。

弱类型:id

在使用常规命名的方式时,应避免使用id。尽量使用具体的类取而代之。

合理使用全局变量与单例

推荐做法

  避免大量的单例
  对子对象使用__strong
  对父对象使用__weak
  对使引用图闭合的对象(如委托)使用__weak
  对数值属性,使用assign
  对块属性,使用copy限定符
  当声明使用NSError**参数的方法时,需要使用__autoreleasing。并注意用正确的语法: NSError*__autoreleasing *。
  避免在块内直接引用外部的变量。在外用weakify,在内strongify
  销毁计时器、移除观察者、解除回调(例如:委托设置为nil)

扩展

依赖注入(Typhoon和Objection框架)
Instruments进行内存分析

你可能感兴趣的:(性能之内存管理)