我的应用程序中遇到内存泄漏,它似乎来自CALayer。它看起来好像只影响旧的iPad;我看到了iPad 1和iPad的问题。 2,但iPad Air还可以。我有一张来自iPad 1的崩溃报告显示我的应用程序由于内存不足而被“抛弃”,这次泄漏是我的主要嫌疑人。
背景
在操作期间,各个UIViews上的网络线程每隔40ms连续调用setNeedsDisplay来更新其视觉效果,请参阅下面的函数。
- (void)setNeedsRepaint
{
[self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
}
模拟iPad2并使用分配工具,我看到每次调用setNeedsDisplay时,malloc 64引用计数都会永久上升。负责的库是libdispatch.dylib,调用者是dispatch_continuation_alloc_from_heap。
iPad Air模拟器没有显示此问题,在这种情况下,malloc 32引用计数仅暂时上升。
即使在setNeedsDisplay源自GUI线程且未通过performSelectorOnMainThread调度的情况下,我看到malloc 64引用计数也在上升。
以下是分配工具的屏幕截图。标记为3的malloc是有问题的泄漏。 mallocs标记为1& 2泄漏要慢得多,但仍然是一个小问题。
采取的步骤
为了排除drawRect中的内存泄漏,我注释掉了大括号之间的所有代码,但泄漏的内存仍在继续累积。
如果我没有覆盖drawRect方法,我没有看到泄漏,但我需要绘制和更新我的视图。如果没有调用setNeedsDisplay,我也不会看到它,我可以通过performSelectorOnMainThread调用虚函数,而不会发生内存泄漏。
我尝试使用块和dispatch_async而不是performSelectorOnMainThread来在GUI线程上运行setNeedsDisplay。
我还尝试减少应用程序,以便仅在单个视图上重复调用setNeedsDisplay。然后移除所有指向该视图的指针,以便ARC清理它,希望可以用它清理迷路mallocs。
我已尝试直接设置CALayer内容,而不是调用setNeedsDisplay。它呈现,但malloc计数以完全相同的方式上升。
self.layer.contents = (__bridge id) _dummyCGImageRef;
在阅读this后,我认为泄漏可能是由于队列变得淹没。但是,将函数调用率降低10只会使内存泄漏速度增加10倍。
结论
泄漏实际上似乎与CALayer而不是调度队列和performSelectorOnMainThread相关联。看起来这个问题在以后的iPad中已得到修复,但我仍然需要针对旧型号的解决方法。
问题
有没有人有任何关于调试的提示?
另一种仪器更适合找到确切的原因吗?
这是模拟器的特性吗?我看到的不是我的应用程序放弃的原因吗?
任何人都知道造成这种情况的原因是什么?这是一个历史性的错误,因为它不会影响iPad Air吗?
我有一个子类化技巧我可以用CALayer来防止后备存储分配内存,或者我更新我的视图视觉效果的其他方式?
感谢。