【问题标题】:iOS 8.1 iPad Air 2 - Image loading memory erroriOS 8.1 iPad Air 2 - 图像加载内存错误
【发布时间】:2014-10-25 23:14:06
【问题描述】:

尽量简洁地解释问题.. 我编写了一个应用程序,该应用程序使用带有 Grand Central Dispatch 的多线程将一系列非常大的 png 强制加载到内存中,并将其加载到 UIImageView 动画序列中。直到最近一直在 iPad Air 1(具有 1GB 的 RAM)上进行测试,在应用程序崩溃之前,我只能将这些 1.7MB 的图像中的大约 40 张加载到内存中。很公平。但是现在有了 iPad Air 2,我渴望得到 2GB 的 RAM,这应该足以轻松获得我的 180 x 1.7MB png 图像的整个序列(是的,我知道,但请和我一起运行)完全进入记忆,然后一些。但令我沮丧的是,在控制台中出现以下错误之前,它似乎只能将其中的 111 个放入内存;

-[_CSIRenditionBlockData _allocateImageBytes] 为 CoreUI 渲染分配图像块数据失败 2014-10-24 20:21:55.592 TestApp[280:19701] CoreUI:解码 CSI/ZIP 压缩图像块数据时出错(行 1280 行字节 10240 格式 0)

2GB 内存肯定能够处理完整的图像序列,超过三倍,确定吗?上述错误暗示了什么?任何人都可以帮忙吗?我真的希望 Air 2 能把它打出公园,到目前为止,我已经跌跌撞撞地走出了大门。

强制图片加载代码就是用这种方法执行的;

+ (UIImage*)imageImmediateLoadWithContentsOfFile:(NSString*)path {

    UIImage* image = [UIImage imageWithContentsOfFile:path];

    CGFloat w = image.size.width;
    CGFloat h = image.size.height;

    CGFloat scale = image.scale;

    if (image.scale > [[UIScreen mainScreen] scale]) {

        scale = 1.0f;

    } else {

        //NSLog(@"SCREEN SCALE LEAVE ALONE\n");
    }

    CGImageRef cgImage = [image CGImage];

    CGContextRef context = CGBitmapContextCreate(NULL, w*scale, h*scale, CGImageGetBitsPerComponent(cgImage), CGImageGetBytesPerRow(cgImage), CGImageGetColorSpace(cgImage), kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);

    CGContextDrawImage(context, CGRectMake(0, 0, w*scale, h*scale), cgImage);

    CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context);
    UIImage* forcedImage = [UIImage imageWithCGImage:decompressedImageRef scale:scale orientation:UIImageOrientationUp];

    CGImageRelease(decompressedImageRef);

    CGContextRelease(context);

    return forcedImage;

}

Grand Central Dispatch 在以下函数中与 dispatch_apply 一起使用;

- (void)startImageLoading {

    dispatch_group_async(hardloadGroup, concurrentBackgroundQueue, ^{

        if (abort) return;

        if (targetSlot == 1 || targetSlot == 3) {

            updateLoadingBar = YES;
            loadingProgress = 0.0f;
            loadingIncrement = 1.0f/(float)framecount;

        }

        dispatch_apply(framecount/FLICKBOOK_STRIDE, concurrentBackgroundQueue, ^(size_t i) {

            if (abort) return;

            size_t current = i * FLICKBOOK_STRIDE + 1;
            size_t end = current + FLICKBOOK_STRIDE;

            do {

                if (updateLoadingBar) [self incrementLoadingBar];

                [self hardloadImageForFrame:current++];

            } while (current < end && !abort);

        });

        if (!abort) {

            // MOP-UP ANY LEFTOVER FRAMES AFTER THE STRIDE DIVISION /////////////////////////////////////////////////////////

            for (size_t i = framecount - (framecount % FLICKBOOK_STRIDE) + 1; i <= framecount; i++) {

                if (abort) break;

                if (updateLoadingBar) [self incrementLoadingBar];

                [self hardloadImageForFrame:i];

            }

        }

    });

    // WRITE THE CONTENTS OF THE DICTIONARY TO THE IMAGE ARRAY IN ORDER /////////////////////////////////////////////

    dispatch_group_notify(hardloadGroup, concurrentBackgroundQueue, ^{

        if (!abort) [self performSelectorOnMainThread:@selector(showFlickbook) withObject:nil waitUntilDone:YES];

        [showcaseViewController loadingThreadFinished];

    });

}


- (void)hardloadImageForFrame:(size_t)frame {

    UIImage* forcedImage = [UIImage imageImmediateLoadWithContentsOfFile:[imageNames objectAtIndex:frame-1]];

    @synchronized(self) { [imageArray replaceObjectAtIndex:frame withObject:forcedImage]; }

}

有人知道是什么原因造成的吗?

【问题讨论】:

  • 很抱歉克劳斯,你评论得太快了,我没有机会添加我所有的代码。请参阅上面的代码示例。不过,我认为仓促的否决有点苛刻。

标签: ios ipad memory png grand-central-dispatch


【解决方案1】:

嗯,这个错误显然是内存分配问题。看起来您正在将这些 1.7Mb png 文件解压缩为每个 12.5Mb 左右(在错误中 - 每个 10240 字节有 1280 行)。 111 批 12.5Mb 将使用大约 1.4Gb。所以我认为你已经达到了可以加载的最大值,因为 iOS 和其他应用程序将使用其中的一些 2Gb。

不确定您为什么要“强制加载这些” - 大概是性能问题?您知道耗时位是来自读取文件还是来自解压缩 png?如果是前者,您可以尝试将文件预加载为 NSData 对象,然后使用 UIImage 的 imageWithData: 方法或 CGImageSourceCreateWithData 即时构建图像。

【讨论】:

  • 感谢 pbasdf,这完全有道理。由于解压缩,我没有考虑到扩展!它本质上是一个交互式轻弹书,强制加载的原因是为了使图像从完整序列呈现为所有图像将需要立即快速连续显示。如果没有这个,图像实际上需要在它们完全进入内存之前被渲染到屏幕缓冲区,所以在它们完全响应之前它会在第一次播放时产生非常缓慢的播放。如果这是有道理的。
  • 附言。如果你能给我的问题一个赞成票以帮助它至少摆脱负面标记,我真的很感激,因为一些过分渴望的“专业人士”双重反对它,因为它是一个“糟糕的书面问题”——原文如此。谢谢:)
  • 这里的答案非常正确,因为您分配了所有可用内存并导致崩溃,所以您的设备正在崩溃。您不能将所有图像“强制”到内存中。在这个答案stackoverflow.com/questions/8112698/… 中了解更多关于更好方法的信息
猜你喜欢
  • 2016-02-05
  • 1970-01-01
  • 2014-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-31
相关资源
最近更新 更多