【问题标题】:CGBitmapContextCreate on the iPhone/iPadiPhone/iPad 上的 CGBitmapContextCreate
【发布时间】:2023-03-14 04:23:01
【问题描述】:

我有一个方法需要逐个像素地解析一堆大的 PNG 图像(每个 PNG 是 600x600 像素)。它在模拟器上似乎工作得很好,但在设备(iPad)上,我在一些内存复制功能中得到了 EXC_BAD_ACCESS。似乎尺寸是罪魁祸首,因为如果我在较小的图像上尝试它,一切似乎都有效。下面是与内存相关的方法。

+ (CGRect) getAlphaBoundsForUImage: (UIImage*) image 
{    
    CGImageRef imageRef = [image CGImage];

NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
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);

CGColorSpaceRelease(colorSpace);

CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);

/* non-memory related stuff */

free(rawData);

当我在一堆图像上运行它时,它运行了 12 次然后出现问题,而在模拟器上它运行没有问题。大家有什么想法吗?

【问题讨论】:

    标签: iphone memory ipad cgcontext


    【解决方案1】:

    运行 12 次然后崩溃听起来像是内存不足的问题。可能是 CGContext 在内部创建了一些大型的自动释放结构。由于您在循环中执行此操作,因此它们不会被释放,因此您会耗尽内存并死掉。

    我不确定 Core Foundation 如何处理临时对象。我不认为 CF 对象具有自动释放功能,Core Graphics 上下文几乎可以肯定处理的是 CF 对象而不是 NSObjects。

    为了减少代码中的内存流失,我建议在开始处理之前对其进行重构以创建一个屏幕外 CGContext,并重复使用它来处理每个图像。然后在完成后释放它。在任何情况下都会更快(因为您不会在每次通过循环时分配巨大的数据结构。)

    我敢打赌,这将消除您的崩溃问题,而且我敢打赌它还会使您的代码变得更快、更快。与其他操作相比,内存分配非常慢,而且您需要使用一些相当大的数据结构来处理 600x600 像素的 RGBA 图像。

    【讨论】:

      【解决方案2】:

      转到产品 -> 编辑方案 -> 启用僵尸对象。在启用僵尸对象之前打勾。现在构建并运行它。它可以为您提供更好的 EXC_BAD_ACCES 错误描述。

      【讨论】:

        【解决方案3】:

        我使用 CGImageCreate() 在我的 iPad(当然是 iPhoneOS 3.2)上遇到了类似的崩溃。看到你的困难给了我一个提示。我通过将我的 bytesPerRow 与 2 的下一个最大幂对齐来解决了这个问题。

        size_t bytesPerRowPower2 = (size_t) round( pow( 2.0, trunc( log((double) bytesPerRow) / log(2.0) ) + 1.0 ) );

        如果提供 2 行对齐功能也可以解决您的问题,请告诉我们。您需要分配具有调整后大小的 *rawData 并将 bytesPerRowPower2 传递给 CGBitmapContextCreate()... 高度似乎不需要对齐。

        【讨论】:

          【解决方案4】:

          也许是 CGImageGetBytesPerRow(两个的幂听起来过分了)。

          【讨论】:

            【解决方案5】:

            当我以编程方式创建图像时,我在直接定义行大小的应用程序中使用了两个对齐行大小的幂。但我也建议 toastie 在尝试我的建议之前先尝试 CGImageGetBytesPerRow。

            【讨论】:

              【解决方案6】:

              尝试在设备上运行应用程序时运行仪器分配,这可能是与内存相关的问题。如果您处于循环中,请在该循环内创建一个自动释放池。

              【讨论】:

                【解决方案7】:

                可能替换

                CGColorSpaceRelease(colorSpace);
                CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
                

                CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
                CGColorSpaceRelease(colorSpace);
                

                因为颜色空间 ref 可能仍然需要某种方式?只是随机猜测... 甚至可能把它放在上下文发布的后面?

                // cleanup
                CGContextRelease(context);
                CGColorSpaceRelease(colorSpace);
                

                【讨论】:

                  【解决方案8】:

                  我通过制作方形上下文(宽度=高度)解决了这个问题。我有一个 512x256 的纹理,每次将数据发送到 OpenGL 时它都会崩溃。现在我分配了一个 512x512 的缓冲区,但仍然渲染 512x256。希望这会有所帮助。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2016-07-21
                    • 2011-06-25
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多