一、核心设计思路
-
基于对象释放的延迟检测
- 原理 :在
UIViewController
被销毁(如pop
或dismiss
)时,延迟一定时间(如 2-3 秒)后检查其是否仍存在强引用。若存在,则判定为内存泄漏。 - 实现 :通过 Hook
UIViewController
的viewDidDisappear:
方法触发检测逻辑,利用weak
弱指针观察对象是否存活。
- 原理 :在
-
循环引用链分析
- 若检测到泄漏,进一步通过工具(如
FBRetainCycleDetector
)分析对象间的强引用关系,定位循环引用链条。
- 若检测到泄漏,进一步通过工具(如
-
白名单与误判处理
- 支持白名单机制,排除单例、缓存对象等无需释放的场景。
二、具体实现步骤
1. Hook 生命周期方法
使用 Method Swizzling 替换 UIViewController
的 viewDidDisappear:
方法,在视图消失时启动检测:
+
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
swizzleMethod([self class], @selector(viewDidDisappear:), @selector(swizzled_viewDidDisappear:));
});
}
- (void)swizzled_viewDidDisappear:(BOOL)animated {
[self swizzled_viewDidDisappear:animated];
if (self.isMovingFromParentViewController || self.isBeingDismissed) {
[self willDeallocCheck]; // 触发泄漏检测
}
}
2. 延迟检测存活状态
通过 dispatch_after
延迟检查对象是否释放:
-
if ([self isInWhitelist]) return NO; // 跳过白名单对象
__weak id weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
__strong id strongSelf = weakSelf;
if (strongSelf) {
[strongSelf assertNotDealloc]; // 触发断言或弹窗报警
}
});
return YES;
}
- (void)assertNotDealloc {
NSAssert(NO, @"%@ 发生内存泄漏!", NSStringFromClass([self class]));
}
3. 遍历视图树检测子对象
检查 UIViewController
的视图及其子视图是否泄漏:
-
[self.view.subviews enumerateObjectsUsingBlock:^(__kindof UIView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if (![obj willDealloc]) {
NSLog(@"子视图 %@ 可能泄漏", obj);
}
}];
}
4. 结合循环引用检测工具
集成 FBRetainCycleDetector
,在断言触发时自动分析引用链:
-
FBRetainCycleDetector *detector = [FBRetainCycleDetector new];
[detector addCandidate:self];
NSSet *retainCycles = [detector findRetainCycles];
NSLog(@"循环引用链:%@", retainCycles);
}
三、优化与注意事项
-
性能优化
- 仅在 Debug 模式 启用检测,避免影响线上性能。
- 使用缓存机制减少重复检测。
-
误判处理
- 区分延迟释放 与真实泄漏:某些对象可能因异步任务延迟释放,需多次检测确认。
- 支持动态白名单,允许开发者标记无需检测的类。
-
扩展性
- 支持自定义检测时间阈值(如从 2 秒调整为 5 秒)。
- 可扩展至检测其他对象(如
UIView
、自定义模型)。
四、验证与工具对比
方法 | 优点 | 缺点 |
---|---|---|
手动检测 dealloc | 简单直接,无侵入性 | 需反复操作,无法自动化 |
Instruments | 全面分析内存分配与泄漏 | 操作复杂,需主动触发,实时性差 |
MLeaksFinder | 自动报警,精准定位泄漏对象 | 需结合其他工具分析循环引用 |
本方案 | 自动化 + 循环引用分析 + 低侵入性 | 需集成第三方库(如 FBRetainCycleDetector) |
五、实践建议
- 开发阶段集成 :通过 CocoaPods 引入检测库(如
MLeaksFinder
),仅启用 Debug 配置。 - CI/CD 流程:在自动化测试中增加内存泄漏检测步骤,结合日志分析工具统计泄漏点。
- 团队规范:在代码 Review 中强制要求修复泄漏报警,避免技术债务累积。
通过上述机制,开发者可高效定位并修复 UIViewController
内存泄漏问题,提升应用稳定性。