Day13-内存泄漏排查、僵尸对象与 MRC 回顾

YVTU

一、iOS内存泄漏排查

1. 常见内存泄漏场景

  • 循环引用:对象之间相互强引用(如父子对象、Block捕获self未使用weak修饰),导致无法释放516
  • 未释放Core Foundation对象:使用CF框架(如CFArrayRefCGImageRef)时未调用CFRelease17
  • 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修饰符避免野指针,自动置nil58
  • MRC下的规范:遵循retain/release配对原则,释放后指针置nil38

三、MRC(Manual Reference Counting)回顾

1. 核心规则

  • 手动管理引用计数:通过retain增加计数,release减少计数,autorelease延迟释放17
  • 所有权原则:谁创建(alloc/new/copy)、谁释放;其他情况需显式retain79
  • Setter方法规范
    1
    2
    3
    4
    - (void)setObject:(id)newObject {
    [_object release]; // 释放旧值
    _object = [newObject retain]; // 保留新值
    }
    需注意旧值可能已被释放的风险9

2. 常见问题与陷阱

  • 不平衡的retain/release:导致内存泄漏或过度释放17
  • 循环引用:需手动打破强引用链(如使用assign替代retain516
  • Autorelease Pool管理:大量临时对象需手动控制释放时机,避免内存峰值9

3. ARC的优势

  • 自动化:编译器自动插入retain/release代码,减少人为错误17
  • 安全性:通过weakstrong修饰符管理所有权,避免僵尸对象57

四、总结与建议

  1. 优先使用ARC:减少手动管理风险,但需注意与Core Foundation交互时的桥接(__bridgeCFRelease17
  2. 规范代码习惯
    • 避免循环引用,使用weak/unowned修饰Block捕获对象5
    • 及时释放非OC对象(如C语言malloc分配的内存)17
  3. 结合工具排查:定期使用静态分析、动态检测和内存图谱,定位复杂泄漏问题61317

通过上述方法,开发者可有效降低内存泄漏风险,提升应用稳定性。