Day13-内存泄漏排查、僵尸对象与 MRC 回顾
一、iOS内存泄漏排查
1. 常见内存泄漏场景
- 循环引用:对象之间相互强引用(如父子对象、Block捕获self未使用
weak
修饰),导致无法释放516。 - 未释放Core Foundation对象:使用CF框架(如
CFArrayRef
、CGImageRef
)时未调用CFRelease
17。 - NSTimer/CADisplayLink强引用:未在适当时机调用
invalidate
,导致持有者无法释放516。 - 大对象未释放:如缓存图片、视频资源未及时清理416。
- ARC下的隐式泄漏:指针提前置
nil
,导致堆对象未被释放(如Person *p = [Person new]; p = nil;
)3。
2. 排查工具与方法
- 静态分析(Analyze):通过Xcode的
Product -> Analyze
检测代码逻辑错误(如访问未初始化指针、未释放路径)1113。 - 动态分析(Instruments):
- Leaks:检测未释放的内存泄漏,结合Call Tree定位代码位置61215。
- Allocations:监控内存分配趋势,识别异常增长区域17。
- Debug Memory Graph:可视化对象引用关系,快速发现循环引用613。
- 第三方工具:如腾讯的
MLeaksFinder
,自动化检测页面泄漏6914。
二、僵尸对象(Zombie Objects)
1. 定义与成因
- 僵尸对象:已被释放(
dealloc
)但仍在被访问的对象,访问时会导致EXC_BAD_ACCESS
崩溃818。 - 常见场景:
- 过度释放:对同一对象多次调用
release
(MRC下)8。 - 野指针:指针指向已释放对象后未置
nil
(如MRC下悬垂指针)818。
- 过度释放:对同一对象多次调用
2. 检测与解决
- 启用Zombie Instrument:在Instruments中选择
Zombies
模式,捕获访问僵尸对象的行为817。 - ARC下的防护:通过
weak
修饰符避免野指针,自动置nil
58。 - MRC下的规范:遵循
retain
/release
配对原则,释放后指针置nil
38。
三、MRC(Manual Reference Counting)回顾
1. 核心规则
- 手动管理引用计数:通过
retain
增加计数,release
减少计数,autorelease
延迟释放17。 - 所有权原则:谁创建(
alloc
/new
/copy
)、谁释放;其他情况需显式retain
79。 - Setter方法规范:需注意旧值可能已被释放的风险9。
1
2
3
4- (void)setObject:(id)newObject {
[_object release]; // 释放旧值
_object = [newObject retain]; // 保留新值
}
2. 常见问题与陷阱
- 不平衡的retain/release:导致内存泄漏或过度释放17。
- 循环引用:需手动打破强引用链(如使用
assign
替代retain
)516。 - Autorelease Pool管理:大量临时对象需手动控制释放时机,避免内存峰值9。
3. ARC的优势
- 自动化:编译器自动插入
retain
/release
代码,减少人为错误17。 - 安全性:通过
weak
和strong
修饰符管理所有权,避免僵尸对象57。
四、总结与建议
- 优先使用ARC:减少手动管理风险,但需注意与Core Foundation交互时的桥接(
__bridge
、CFRelease
)17。 - 规范代码习惯:
- 避免循环引用,使用
weak
/unowned
修饰Block捕获对象5。 - 及时释放非OC对象(如C语言
malloc
分配的内存)17。
- 避免循环引用,使用
- 结合工具排查:定期使用静态分析、动态检测和内存图谱,定位复杂泄漏问题61317。
通过上述方法,开发者可有效降低内存泄漏风险,提升应用稳定性。