当我创建UIImage实例时,似乎存在内存管理问题,CGImages没有被释放。
我有一个分页UIScrollView来滚动一系列的JPG图像。下面是我的整个类,它是分页滚动视图中的一个页面视图。
代码在主线程上运行。代码使用ARC。我尝试使用imageWithContentsOfFile:(返回一个自动释放的对象)和initWithContentsOfFile:(返回一个保留的对象)加载图像。我尝试了@autoreleasepool和使用performSelectorOnMainThread来确保代码正在主线程上运行,正如其他帖子中建议的那样。
当滚动图片时,内存使用量会不断增长,直到应用程序被终止,如仪器截图所示。请注意,高分配给图像io。
显示虚拟内存使用情况的屏幕截图
在以下截图中,可以看到GTGImageScrollerPageViews、UIImageViews和UIImages已被释放。请注意,这些数字高达300多个。但是CGImages没有被释放,CGImages的数量高达400多个,0个短暂对象。
显示分配的屏幕截图
编辑:以前我一直在ScrollView中回收和重用GTGImageScrollerPageView实例,这是像这样的滚动视图的常见模式。为了简化调试此问题,我允许整个GTGImageScrollerPageView在显示在ScrollView后被释放。如上面的第二张图所示,只有4个GTGImageScrollerPageView存活,377个短暂对象,还有388个UIImageViews和389个UIIMages被列为短暂对象,因此似乎UIImageViews和UIImages已经被很好地释放了。
如果我手动使用CGImageRelease释放CGImage(在下面的代码中注释掉),则CGImages将被释放。我知道我不应该这样做,因为我不拥有CGImage,但这对于验证问题出现的位置非常有用。下面的截图显示了在使用CGImageRelease进行测试的相同代码,但是CGImageRelease未被注释掉。
使用CGImageRelease显示虚拟内存使用情况的屏幕截图
使用CGImageRelease显示分配的屏幕截图
在使用CGImageRelease的分析输出中,可以看到正确数量的CGImage对象是Living和Transitory,并且内存不会无限增长。此外,在使用CGImageRelease时,应用程序在使用过程中不会崩溃。
如果这是CGImage的一些系统缓存,那么当内存警告发生时,它应该释放内存,但它没有。内存仍然持续增长。是什么原因导致内存无限增长?
以下是页面视图的代码。
编辑:回应评论后,我已经更新了代码,进一步简化了代码。消除了不需要演示问题的实例变量和属性等干扰因素,但问题并没有改变。在分析时结果是相同的。我还添加了NSLog,它会输出线程。我确实看到了GTGImageScrollerPageView上的dealloc被调用,它总是线程#1,并且对displayAspectThumbImage的调用始终在线程#1上。
我真的不认为这里呈现的代码有任何问题,这得到了Rob的大力支持。其他事情导致了这个问题,但是所有与加载和显示图像相关的代码都在这里;这里没有其他代码。我唯一能想到的值得注意的另一件事是displayAspectThumbImage方法是从scrollviewDidScroll和scrollViewDidEndDecellerating滚动视图委托方法中调用的,但是由于这些方法在主线程上运行,所以应该排除由于在另一个线程上运行而造成的autorelease问题。
我已经检查过,NSZombies未启用,也没有正在增加我的内存使用。实际上,当调用CGImageRelease方法时,内存使用情况非常平稳,如上面的屏幕截图所示。
@implementation GTGImageScrollerPageView
- (void)dealloc {
NSLog(@"%s %@", __PRETTY_FUNCTION__, [NSThread currentThread]);
}
- (void)displayAspectThumbImage:(NSString *)path {
NSLog(@"%s %@", __PRETTY_FUNCTION__, [NSThread currentThread]);
UIImageView *imageView = [[UIImageView alloc] initWithFrame:self.bounds];
[self addSubview:imageView];
UIImage *image = [[UIImage alloc] initWithContentsOfFile:path];
[imageView setImage:image];
//If uncommented CGImages are disposed correctly
//CGImageRelease([imageView.image CGImage]);
}
@end
测试环境:
iOS 6.1.4
iOS 5.0.1
CGImage
不是正确的解决方案。你展示了图片视图的创建过程,但是你有删除它吗?当滚动浏览图像时,你应该删除旧的图片视图,然后再添加新的。你这样做了吗? - Rob