给令人头疼的内存和崩溃问题一个解决思路

1,677 阅读3分钟

应用开发到一定规模后,各种内存问题频频出现,还很难定位。你是否也体会过这种痛苦?

内存问题

随着我们工程的体量增长,代码结构变得越来越复杂。这时候很多内存问题就变得越来越难解决。一个不小心的循环引用就会导致一部分内存被一直占用。而这样的内存泄露一般都会随着代码量的增长不断的引入到项目中。往往到了最后,这个问题就不了了之了。

还好现在手机的内存越来越大,但即使这样,当你的工程越来越大之后,这些不断引入的内存问题,一定会对你应用的稳定性有越来越多的影响。

FBMemoryProfiler

正因为这样的问题,今天给大家介绍 Facebook 的一个开源库 FBMemoryProfiler。 github.com/facebook/FB…

我们应用中导致内存泄露的元凶大多是循环引用。 所谓循环引用就是几个实例互相使用 strong 引用对方,最后导致谁也释放不掉谁。

FBMemoryProfiler 是几个组件的结合。其中包括 FBAllocationTracker 和 FBRetainCycleDetector。

FBAllocationTracker 用于检测应用在运行时所有实例的分配。它的原理其实就是用 method swizzling 替换原本的 alloc 方法。这样就可以记录下所有的实例分配了。使用起来也不难,在工程的 main 函数中初始化:

#import 
int main(int argc, char * argv[]) {
  [[FBAllocationTrackerManager sharedManager] startTrackingAllocations];
  [[FBAllocationTrackerManager sharedManager] enableGenerations];
  @autoreleasepool {
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
  }
}

然后在需要的时候调用 currentAllocationSummary 方法,就可以得到当前整体的实例分配情况:

NSArray<FBAllocationTrackerSummary *> *summaries = [[FBAllocationTrackerManager sharedManager] currentAllocationSummary];

有了 FBAllocationTracker, 我们可以记录应用中所有的示例分配。 但还需要另一个组件 FBRetainCycleDetector 才能完成循环引用的检测。

FBRetainCycleDetector 接受一个运行时的实例,然后从这个实例开始遍历它所有的属性,逐级递归。 如果发现遍历到重复的实例,就说明存在循环引用,并给出报告。

FBRetainCycleDetector *detector = [FBRetainCycleDetector new];
[detector addCandidate:myObject];
NSSet *retainCycles = [detector findRetainCycles];
NSLog(@"%@", retainCycles);

上面的代码初始化了 FBRetainCycleDetector 实例, 然后调用 addCandidate 方法添加要检测的实例。 然后调用 findRetainCycles 方法检测循环引用,并输出。

如果存在循环引用,就会输出类似的内容:

{(
    (
        "-> MyObject ",
        "-> _someObject -> __NSArrayI "
    )
)}

通过这个线索,你就可以找到你代码中可能导致循环引用的地方了。

两个基础组件介绍完了, 接下来就是 FBMemoryProfiler。 它其实内部调用的就是这两个组件,然后通过图形界面显示出来, 只需要这样调用,将 UI 界面展示出来:

#import 
FBMemoryProfiler *memoryProfiler = [FBMemoryProfiler new];
[memoryProfiler enable];
// Store memory profiler somewhere to extend it's lifetime
_memoryProfiler = memoryProfiler;

然后启动应用,完整的内存报告就展示出来了:

总结

FBMemoryProfiler 除了可以这样手动调试之外,它还可以进行自动化检测。 通过它内置的两个组件 FBRetainCycleDetector 和 FBAllocationTracker,直接检测出内存中的循环引用,然后把数据发送到自己的服务器上,可以形成一个自动化检测系统。 Facebook 有一篇文章专门介绍这个,大家感兴趣也可以研究一下 code.facebook.com/posts/58394…。 如果你需要对内存引用做深入的优化,这个工具应该能够帮到你。

FBMemoryProfiler 的 Github 主页: github.com/facebook/FB…

如果你觉得这篇文章有帮助,还可以关注微信公众号 swift-cafe,会有更多我的原创内容分享给你~

本站文章均为原创内容,如需转载请注明出处,谢谢。