MRC遵循原理
- 谁创建,谁释放,谁引用,谁管理
- 当引用计数为0的时候,必须回收,引用计数不为0,不能回收,如果引用计数为0,但是没有回收,会造成内存泄露。如果引用计数为0,继续释放,会造成野指针。为了避免出现野指针,我们在释放的时候,会先让指针=nil。
- alloc 分配内存空间
- retain引用计数+1
- release 引用计数-1
- retainCount获取当前对象的引用计数值
- autorelease结束的时候 对autoreleasepool操作进行release -1
- dealloc在MRC当中调用 super dealloc 释放废弃父类的成员变量
ARC注意事项
- ARC是由编译器 跟Runtime共同协作组成ARC的全部功能
- ARC 禁止手动调用retain/release/retainCount/dealloc 并且我们在ARC 重写某个对象的dealloc方法 但是不能再dealloc方法中显示调用super dealloc
- ARC新增 weak strong 两个属性关键字 构成了ARC的全部内容
- ARC与MRC的区别
- MRC是手动管理内存
- ARC是有LLVM跟Rtuntime协作来进行自动引用计数的管理
- MRC可以调用引用计数相关的方法,ARC是不能调用的
- weak 当对象被废弃之后 会调用 dealloc 会调用他的弱引用清除的函数 会根据当前对象指针查找弱引用表 把当前对象相对应的弱引用 都拿出来是个数组 便利数组中所有的
- 弱引用指针 分别nil
循环引用
- 自循环引用 相互循环引用 多循环引用
- 代理 相互循环引用 强引用 若引用 合适的时候手动断开循环引用 __weak __block __unsafa_unretained
- Block解除循环引用
- MRC__block 修饰的对象 不会增加引用计数 避免循环引用
- ARC __block修饰的对象会被强引用,无法避免循环引用,需要手动解环
- __unsafa_unretained 修饰的对象 不会增加其引用计数 避免循环引用
循环引用就是当self 拥有一个block的时候,在block 又调用self的方法。这个时候self强引用了block,而在block中使用self也会强引用self。这样就会产生循环引用,导致两个对象都得不到释放。掐断其中的一条强引用,使之变成弱引用,变成这样,就打破了循环引用:
__weak typeof (self) weakSelf = self;
在使用 NSTimer addtarget 时,为了防止 target 被释放而导致的程序异常,timer 会强引用 target,所以这也是一处内存泄露的隐患。解决方法是使用线程安全的MSWeakTimer,然后在dealloc中主动调用invalidate
- (void)dealloc{
[timer invalidate];
}
内存释放池
- 把需要释放的内存统一放在一个池子中,当池子被抽干后(drain),池子中所有的内存空间也被自动释放掉。内存池的释放操作分为自动和手动。自动释放受runloop机制影响。
- 自动释放池的机制就像“栈”。系统创建好池之后,将其压入栈中,而清空自动释放池相当于将池从栈中弹出。在对象上执行自动释放操作,就等于将其放入位于栈顶的那个池。
- 编译器会将@autoreleasepool 改写为objc_autoreleasePoolPush 里面有个objec_autoreleasePoolPop 一次pop 相当于批量的pop操作 都会添加到自动释放池,发送一次releas操作
- 它是以栈为节点的通过双向链表
- 栈的特点 后入先出低地址 高地址 栈顶 栈底
- 实现原理 以栈为节点 通过双向链表 形式组合而成的数据结构
- 例如下面列子 频繁操作循环 会占用资源 没有必要非要在整个循环结束 释放资源
for (int i=0; i<100000; i++) {
@autoreleasepool{
NSString *str = @"text";
str = [str lowercaseString];
str = [str stringByAppendingString:@"xyz"];
}
}