ARC下紧密循环中UIKit的内存管理

Jon*_*lis 2 iphone cocoa-touch objective-c ios automatic-ref-counting

我有兴趣了解如何在ARC紧密循环下最好地处理内存管理.特别是,我有一个我正在编写的应用程序,它有一个while很长时间的循环,我注意到尽管已经实现了(我相信是)ARC中的最佳实践,但堆仍然存在无限增长.

为了说明我遇到的问题,我首先设置以下测试以故意失败:

while (true) {         
    NSMutableArray *array = [NSMutableArray arrayWithObject:@"Foo"];
    [array addObject:@"bar"]; // do something with it to prevent compiler optimisations from skipping over it entirely
}
Run Code Online (Sandbox Code Playgroud)

使用"分配"工具运行此代码和分析表明内存使用量不断增加.但是,@autoreleasepool如下所示,立即解决问题并保持内存使用的良好和低:

while (true) {
    @autoreleasepool {         
        NSMutableArray *array = [NSMutableArray arrayWithObject:@"Foo"];
        [array addObject:@"bar"];
    }
}
Run Code Online (Sandbox Code Playgroud)

完善!这一切似乎都运行良好 - 它甚至可以正常工作(如预期的那样)用于使用创建的非自动释放的实例[[... alloc] init].一切正常,直到我开始涉及任何UIKit课程.

例如,让我们创建一个UIButton并看看会发生什么:

while (true) {
    @autoreleasepool {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        button.frame = CGRectZero;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,内存使用量无限增加 - 实际上,它似乎@autoreleasepool没有任何效果.

所以问题是为什么@autoreleasepool工作正常NSMutableArray并保持内存检查,但是当应用于UIButton堆继续增长?

最重要的是,UIKit在这样的无限循环中使用类时,如何保持堆不断扩展?这告诉我们ARC while(true)while(keepRunningForALongTime)样式循环的最佳实践?

我对此的直觉是(而且我可能完全错了)是,它可能是关于如何while (true)使runloop保持循环,这是将UIKit实例保留在记忆中而不是释放它们......但很明显我错过了一些东西我对ARC的理解!

(并且消除了明显的原因,NSZombiedEnabled未启用.)

bbu*_*bum 5

至于为什么UI*对象无限制地增长?内部实施细节.最有可能的是,通过阻止主运行循环有效禁用某种缓存或runloop交互.

这让我得到了真正的答案:

最重要的是,在这样的无限循环中使用UIKit类时,如何让堆不断扩展?这告诉我们在while(true)或while(keepRunningForALongTime)样式循环中ARC的最佳实践?

怎么解决? 不要在主线程上使用紧密循环,不要阻止主运行循环.

即使您要弄清楚UI*引起的堆增长,如果您while(...)在主线程上使用循环,您的程序仍然无法工作.iOS应用程序(和Cocoa应用程序)的整个设计是主线程有一个主运行循环,主运行循环必须可以自由运行.

如果不?您的应用程序将不会响应(并最终将被系统杀死)到用户输入,并且您的绘图代码不太可能按预期工作(因为运行循环合并脏区域并根据需要与主线程一起绘制它们,oft卸载到辅助线程).