【问题标题】:Memory leak with renderInContext and UIImagePNGRepresentationrenderInContext 和 UIImagePNGRepresentation 的内存泄漏
【发布时间】:2015-10-31 23:46:01
【问题描述】:

通过将不可见视图渲染到上下文中来创建图像时,我发现大量内存泄漏。我已将其简化为最基本的实现,并确定了导致内存泄漏的两行代码:renderInContextUIImagePNGRepresentation。如果我将两者都注释掉,则不会发生泄漏,但如果其中一个未注释,则会发生泄漏,如果两者都未注释,则会发生两次泄漏。 每次调用下面的方法时,内存使用量都会显着增加(如预期的那样),然后过一会儿它会减少,但比调用前的量高约 0.8 MB。

如何解决此问题以确保没有内存泄漏?

public class func imageDataForSymbol(symbol: String) -> NSData? {
    var imageData: NSData!

    let dimension = 180

    let label = UILabel(frame: CGRectMake(0, 0, CGFloat(dimension), CGFloat(dimension)))
    label.text = symbol

    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let bitmapInfo = CGImageAlphaInfo.PremultipliedLast.rawValue
    let bitmapContext = CGBitmapContextCreate(nil, dimension, dimension, 8, 0, colorSpace, bitmapInfo)!

    label.layer.renderInContext(bitmapContext) //FIXME: causing leak!!

    let cgImage = CGBitmapContextCreateImage(bitmapContext)!
    let image = UIImage(CGImage: cgImage)
    imageData = UIImagePNGRepresentation(image)! //FIXME: causing leak!!

    return imageData
}

为了测试它,在viewDidAppear:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
        NSData *d = [ImageGenerator imageDataForSymbol:@"W"];

        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"triggered");
        });
    });
});

如果有更好的方法为UILabellayer 的图像创建NSData,我完全赞成。我想不出其他方法来获得它,除了从CGImage 创建一个CIImage 然后从CIImageUIImage 然后从UIImageNSData。请注意,它不需要很快,但它确实需要在后台线程上创建图像,以确保 UI 保持对额外输入的响应。

【问题讨论】:

  • @matt 使用模拟器,稍后将在 iPad 上尝试发布模式并报告!这并不像看起来那么奇怪,我正在做更多花哨的事情,而不仅仅是一个标签,这是显示泄漏的精简代码。我会像往常一样渲染它,但是在后台线程上弄乱 UIKit 是一个很大的禁忌,我需要应用程序在发生这种情况时继续响应。
  • @matt UIGraphicsBeginImageContext 方法是我最初采用的方法,但它不应该在后台线程上运行,我不能在主线程上运行它 - 请参阅下面链接的问题。我现在采用的方法是答案中显示的方法:改用 Core Graphics。 stackoverflow.com/questions/12843777/…
  • 在后台线程的 UIGraphics 上下文中呈现标签不起作用...文本不会出现。 stackoverflow.com/questions/30512053/…
  • 使用 UIKit 方法绘制字符串的另一个问题是,生成的图像的文件大小比使用 UILabel 和 Core Graphics 方法生成的图像大近 3 倍。

标签: ios swift memory-leaks core-graphics


【解决方案1】:

将 CGColorSpaceCreateDeviceRGB 与 CGColorSpaceRelease 配对

将 CGBitmapContextCreate 与 CGContextRelease 配对

将 CGBitmapContextCreateImage 与 CGContextRelease 配对

【讨论】:

  • 从技术上讲,Swift 不管理内存,它是 ARC 完成繁重的工作......
  • 真的吗?但是在带有 ARC 的 Obj-C 中,我总是使用 *Release 函数,它们运行良好。我记得,ARC 不管理 Core Foundation 的内存。
猜你喜欢
  • 2014-10-08
  • 2012-08-05
  • 2017-02-20
  • 1970-01-01
  • 2010-12-02
  • 2013-11-08
  • 2016-05-03
  • 2011-11-25
  • 2010-11-19
相关资源
最近更新 更多