加载 UIImage 时 iOS 应用程序崩溃(虚拟内存未清理)

Posted

技术标签:

【中文标题】加载 UIImage 时 iOS 应用程序崩溃(虚拟内存未清理)【英文标题】:iOS Application Crash while UIImage loading (virtual memory not cleaning up) 【发布时间】:2013-05-29 04:52:16 【问题描述】:

我的应用程序发生了奇怪的崩溃,没有任何痕迹。这可能是与内存相关的问题,但信息很少,我不确定如何继续或修复它。如果不是因为乐器,就永远不知道是什么了。

我有一个图像数组(在此示例中为大小为 2 的数组),我在其中加载图像,创建图像上下文并绘制并将其保存到数组中。每次调用该方法时,图像数组对象都会被新内容替换。在仪器中,我在此方法调用期间看到非常巨大的虚拟内存使用量,显然在每次调用内存未清除之后,因此崩溃。该项目是ARC。我将在下面列出代码。这就是我们重新创建此问题所需的全部内容。 (我使用的图像大小约为 7MB,因此更容易重新创建崩溃)。我也在使用 iPad2 设备。

+ (UIImage *)imageCopy:(UIImage *)src

    UIGraphicsBeginImageContext(src.size);
    [src drawAtPoint:CGPointZero];
    UIImage *r = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return r;
 

- (IBAction)buttonTouch:(id)sender

    for (int i=0; i<2; i++)
    
        if (i==0)
        
            self.mImage = [UIImage imageNamed:@"LARGE_elevation.jpg"];
        
        else
        
            self.mImage = [UIImage imageNamed:@"LARGE_elevation2.jpg"];
        
        // imageArray is a NSMutableArray with capacity of 2
        [imageArray setObject:[ViewController imageCopy:self.mImage] atIndexedSubscript:i];
    
    ((UIImageView *)[self.view viewWithTag:100]).image = self.mImage;

这是仪器的屏幕,在发出内存警告后第二次崩溃。

我没有看到我在这里使用的“imageCopy”方法有什么大问题。

非常感谢您对此的任何帮助。 谢谢和干杯,

【问题讨论】:

"我有一个图像数组(在这个例子中是一个大小为 2 的数组),我在其中加载了一个图像..." "我使用的图像有点大,大约 7MB... " 显然,这不是明智之举。 【参考方案1】:

我发现这是一个循环引用问题。因此,当新内容替换数组中的旧内容时,过去的对象仍然存在。这是一个非常有趣的发现,因为在内存泄漏分析器中它显示的数据泄漏只有几 KB,您不会怀疑这是因为未释放的虚拟内存只有几百兆字节 (MB)。

作为一个非常抽象的例子。

ClassA

@property (strong) ClassB *obj

----------

ClassB

@property (strong) ClassA *obj

- (id)initWithA:(ClassA *)objA;
----------

因此,当您删除 A 时,两个对象都不会被正确释放。在我的情况下,泄漏分析器跟踪的泄漏对于两个对象来说都是几 KB,即使 CoreGraphics 计算挂在虚拟内存中大约 200MB 的数据上。

修复是将 ClassB 中的 A 引用标记为弱。

ClassB

@property (weak) ClassA *obj

- (id)initWithA:(ClassA *)objA;

判决

永远不要低估内存泄漏,无论大小 & arc 或 mrc

【讨论】:

【参考方案2】:

问题可能是 imageNamed: 方法缓存了加载的图像,显​​然没有办法在内存警告后以编程方式清除缓存。 除了imageNamed:,您还可以使用不缓存图像的其他方法,例如initWithData:。你会发现一个详细的讨论here。

【讨论】:

感谢您的意见。但它仍然是相同的结果。同样来自文档,它指出“此方法在系统缓存中查找具有指定名称的图像对象,如果存在则返回该对象。如果匹配的图像对象不在缓存中,则此方法从指定文件加载图像数据,缓存它,然后返回结果对象。" 我认为问题在于 imageNamed: 缓存了多个图像,并且在不再需要图像时不会自动释放内存。但是如果你用非缓存方法得到了同样的结果,那我们再找一个原因……

以上是关于加载 UIImage 时 iOS 应用程序崩溃(虚拟内存未清理)的主要内容,如果未能解决你的问题,请参考以下文章

应用启动时加载用户配置文件,选择视图时崩溃,将 PFFile 转换为 UIImage

加载高清大图崩溃问题

ios8 UIImage imageNamed:崩溃

如何加载包含数百个 UIImage 实例的数组而不会因为内存激增而导致应用程序崩溃?

UIImage 未在视图中加载确实在 iOS 中加载

UIImage * 是 __NSCFArray 而不是 UIImage