【问题标题】:Very high memory usage for CGBitmapContextCreateCGBitmapContextCreate 的内存使用率非常高
【发布时间】:2012-10-30 21:32:01
【问题描述】:

我正在使用以下代码在我的 iOS 应用程序的 touchesEnded 处截取绘图:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

    if(_pagessavedbg.count > selectedIndex)
        self.topimage = [_pagessavedbg objectAtIndex:selectedIndex];

    else
        self.topimage = [UIImage imageNamed:@"BlankImage.png"];

    UIImage *bottomimage = [notification.userInfo objectForKey:@"Image"];

    CGSize size = activeView.frame.size;

    NSUInteger width = size.width * 2;
    NSUInteger height = size.height * 2;

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    unsigned char *rawData = malloc(height * width * 4);
    memset(rawData,0,height * width * 4);

    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGRect bounds;
    bounds.origin = CGPointMake(0,0);
    bounds.size = size;

    CGContextScaleCTM(context, 2.0, 2.0);

    CGContextDrawImage(context, CGRectMake(0, 0, size.width, size.height), [self.topimage CGImage]);
    CGContextDrawImage(context, CGRectMake(0, 0, size.width, size.height), [bottomimage CGImage]);

    CGImageRef imageRef2 = CGBitmapContextCreateImage(context);
    UIImage *latest2 = [UIImage imageWithCGImage:imageRef2 scale:0.0 orientation:UIImageOrientationDownMirrored];

    activeView.layer.contentsScale = 2.0;
    [activeView.layer renderInContext:context];

    CGImageRef imageRef = CGBitmapContextCreateImage(context);
    UIImage *latest = [UIImage imageWithCGImage:imageRef scale:0.0 orientation:UIImageOrientationDownMirrored];

    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    CGImageRelease(imageRef);
    CGImageRelease(imageRef2);
    free(rawData);

    [_pages replaceObjectAtIndex:_sidebar.selectedIndex withObject:latest];

    [_sidebar reloadData];

    if(_pages.count > selectedIndex)
    {
    if([_pages objectAtIndex:selectedIndex])
    [_pages replaceObjectAtIndex:selectedIndex withObject:latest];

    if([_pagessavedbg objectAtIndex:selectedIndex])
    [_pagessavedbg replaceObjectAtIndex:selectedIndex withObject:latest2];

    else
    [_pagessavedbg insertObject:latest2 atIndex:selectedIndex];
    }

    dispatch_async(dispatch_get_main_queue(), ^{
    [self.sidebar reloadData];
    [self.sidebar scrollRowAtIndexToVisible:_sidebar.selectedIndex];
    });    


});

但是,每次调用此代码(在 touchesEnded 时),内存使用量都会增加大约 10MB。为什么会这样?有没有更好的替代方法可以使用更多更少的内存?

【问题讨论】:

  • 您确实意识到这将创建原始图像数据的副本。对于视网膜 ipad,每像素 2048 * 1536 * 4 字节几乎正好是 12mb - 除了在渲染之前缩小视图之外,您无能为力。
  • 所以我无法以任何方式减少如此巨大的内存使用量?
  • 您所说的代码执行期间的内存使用情况不是内存泄漏对吗?
  • 您可以消除图像的 Alpha 通道,这将减少 25% 或 3 MB 的内存使用量。将您的 malloc 更改为 (width * height * 3) 并相应地更改您的 bytesPerPixel 和 bytesPerRow。然后将最后的格式从 kCGImageAlphaPremultipliedLast 更改为 kCGImageAlphaNone。对这些确切的变化不是 100% 肯定,但这应该会让你走上正确的道路。
  • 内存增加是由用于存储位图上下文数据的 malloc 引起的。原始图像使用大量数据,除了我上面提到的之外,你可以做的不多。

标签: iphone objective-c ios xcode memory-management


【解决方案1】:

正如贾斯汀所说,2048 * 1536 * 4 = 12MB。这个事实是数学,无法避免。但是,如果分配 12MB 是一个问题,有很多方法可以管理您的内存利用率(对于短期使用来说,1GB 设备上的内存并不是那么多,所以您应该询问您要解决的问题,但无论如何。 ...)

  • 如果您经常这样做,请不要重新分配内存。重复使用它。这样您只需支付一次。
  • 如果您不需要 2048*1536*4 的图像,请创建一个较小的位图并缩放您的图像以适应它。
  • 分配较小的位图并将部分图像渲染到其中。稍后将它们缝合在一起。

但是你有一个目标内存分配吗?虽然视网膜显示器一直是许多应用程序的主要内存问题,但短暂的 12MB 分配通常不是问题。更多时候是所需的时间,而不是内存。

如果你必须有一个 2048*1536*4 的位图,那么它将占用 12MB 的内存。

【讨论】:

  • 我还要补充一点,您不应该再保留从上述代码生成的 UIImage 超过您需要的时间。在上面的代码中,这张图片似乎被发送到后台保存进程,但您要确保在保存完成后立即释放它。
  • 听完@BradLarson 所说的,保存完成后如何解除分配?
  • @d3v3l0p3r101 - 确保从可能保留它的任何数组或其他集合中删除 UIImage,正确释放它(如果在手动引用计数下),并从所有属性中删除对它的引用.基本上,把它当作任何其他有用性已经结束的对象一样对待。
  • 很好的总结,谢谢。关于创建没有 alpha 通道的位图上下文有什么想法吗?这对渲染图层无效吗?
  • @JustinMeiners: These are the formats that CGBitmapContext supports. 如您所见,没有 24 位或 48 位格式,只有 32 位和 64 位格式,其中每个像素的四分之一用于 alpha 或未使用。
猜你喜欢
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-25
相关资源
最近更新 更多