【问题标题】:struct memory allocation (leaks and crash, profiling on iPhone)结构内存分配(泄漏和崩溃,iPhone 上的分析)
【发布时间】:2014-02-24 18:52:07
【问题描述】:

我有一个结构定义为:

struct VImage
{
    uint8_t *imageData;
    int dimensions[3];
    ...
}

我正在分析我的代码以查找泄漏和其他问题。考虑以下代码:

for (int i = 0; i < 100; i++)
{
    // after we have the image, we use the cheap rgb function to get rgb data
    struct VImage *vImage = [SomeClass someFunction:someArgument];
    free(vImage);
}

这会使我的代码崩溃。我想知道为什么会这样。但是,i &lt; 10 条件不会使应用程序崩溃。对仪器进行分析并没有表明有任何泄漏;但是分配激增,我使用了大量的实时内存;所以我想知道以这种方式释放结构是否正确,或者 free 是否是一个异步函数,它将释放某人的内存,但不仅仅是在我要求它的时候。

编辑:所以我被要求提供这个someFunction 方法的详细信息,我会的。我认为该方法没有内存泄漏,但我还是把它放在这里:

+ (struct VImage *)grayScaleImageDataFromImage:(UIImage *)image
{
    int imageWidth = image.size.width, imageHeight = image.size.height;

    uint32_t *rgbImageData = (uint32_t *) malloc(imageWidth * imageHeight * sizeof(uint32_t));
    memset(rgbImageData, 0, imageWidth * imageHeight * sizeof(uint32_t));

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    // create context with RGBA pixels
    CGContextRef context = CGBitmapContextCreate(rgbImageData, imageWidth, imageHeight, 8, imageWidth * sizeof(uint32_t), colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast);
    CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
    CGContextSetShouldAntialias(context, NO);

    // paint to fill pixels array
    CGContextDrawImage(context, CGRectMake(0, 0, imageWidth, imageHeight), [image CGImage]);
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);

    // now convert to grayscale using CCIR 601 <=> Y' = 0.299 R' + 0.587 G' + 0.114 B'.
    uint8_t *grayScaleImageData = (uint8_t *) malloc(imageWidth * imageHeight);
    for(int y = 0; y < imageHeight; y++)
    {
        for(int x = 0; x < imageWidth; x++)
        {
            uint32_t rgbPixel = rgbImageData[y*imageWidth+x];
            grayScaleImageData[y*imageWidth + x] = 0.299*((rgbPixel>>24)&255) + 0.587*((rgbPixel>>16)&255) + 0.114*((rgbPixel>>8)&255);
        }
    }

    struct VImage *vImage = createGrayScaleDescription(grayScaleImageData, imageHeight, imageWidth);

    free(rgbImageData);
    return vImage;
}

struct VImage *createGrayScaleDescription(uint8_t *grayScaleImage, int height, int width)
{
    struct VImage *vImage = malloc(sizeof(struct VImage));
    vImage->grayScaleImage = grayScaleImage;
    vImage->numberOfDimensions = 2;
    vImage->dimensions[0] = height, vImage->dimensions[1] = width, vImage->dimensions[2] = 1;
    vImage->isGrayscale = true;
    return vImage;
}

所以我所做的就是通过一些计算使用 rgb 数据创建灰度图像。不过,我认为这里没有任何问题。

【问题讨论】:

  • 这取决于someFunction的实现。你能分享它的代码吗?
  • 发布someFunction:someArgument:的代码?
  • @Zaph 它与您提供的链接中的问题无关。 @Merlevede,我已经发布了someFunction 的代码。

标签: objective-c c memory-management struct profiling


【解决方案1】:

一方面,您正在泄漏grayScaleImageData 指向的内存:

在 grayScaleImageDataFromImage 你做

uint8_t *grayScaleImageData = (uint8_t *) malloc(imageWidth * imageHeight);

这很好,然后在createGrayScaleDescription 中设置vImage-&gt;grayScaleImage 指向该内存,这也很好。

但是在你的 1 到 100 循环中,你释放了 vImage 而没有首先释放 vImage-&gt;grayScaleImage 指向的内存。那是内存泄漏。

我认为这不会导致您的应用程序崩溃,但这是您需要修复的问题。没有什么能引起我的注意,但我会仔细看看。

编辑:仔细检查后,您似乎超出了分配给的缓冲区 grayScaleImageData.

你 malloc 使用:

uint8_t *grayScaleImageData = (uint8_t *) malloc(imageWidth * imageHeight);

然后你用以下内容填充该缓冲区:

uint32_t rgbPixel = rgbImageData[y*imageWidth+x];
grayScaleImageData[y*imageWidth + x] = 0.299*((rgbPixel>>24)&255) + 0.587*((rgbPixel>>16)&255) + 0.114*((rgbPixel>>8)&255);

您已分配 (imageWidth * imageHeight) 8 位 uint,但随后您使用 32 位 uint 填充它。

也许这就是导致您崩溃的原因?也许尝试将 malloc 更改为

uint32_t *grayScaleImageData = (uint32_t *) malloc(imageWidth * imageHeight * sizeof (uint32_t));

就像您在上面对 rgbImageData 所做的那样?那,或者将位移计算的结果转换为 uint8_t,然后再将其设置为 grayScaleImageData:

uint32_t rgbPixel = rgbImageData[y*imageWidth+x];
grayScaleImageData[y*imageWidth + x] = (uint8_t)(0.299*((rgbPixel>>24)&255) + 0.587*((rgbPixel>>16)&255) + 0.114*((rgbPixel>>8)&255));

【讨论】:

  • 所以在你回答这个问题之前,我进行了更多研究,并确切地知道你在说什么。但是,我认为 free(vImage) 可以完成这项工作,但我需要在从方法返回 vImage 之前释放 grayScaleImage 指向的内存。这就是我现在与之抗争的方式。我不认为释放vImage-&gt;grayScaleImage 是正确的做法。如果这是正确的方法,您能否发表评论?
  • @flippex17:在你完成之前你不能释放内存,所以不。我已经编辑了我的答案以添加我认为真正的问题。至于内存泄漏,你需要在释放(vImage)之前释放(vImage->grayScaleImage)。
  • 所以 grayScaleImageData 不需要那么多信息。我不认为我超出了缓冲区,因为每次运行它时它都会崩溃。我只输入以 imageWidthimageHeight 为上限的 [yimageWidth + x] 值。此外,这些移位和掩码都是 8 位;所以计算都是8位。不过我会试试你的解决方案。
  • @flippex17:只有最后一个超出缓冲区,正好 3 个字节。位移计算的结果是一个适合 8 位的数字,但它仍然是一个 32 位的计算。最终结果是一个 32 位数字,其高 24 位为零。缓冲区溢出仅在覆盖重要内容时才会导致崩溃,因此它可能不会每次都崩溃。
  • 确实如此。这将导致缓冲区溢出。我不想有一个 32 位的 grayScaleImageData,所以我需要限制计算,使其只有 8 位。不过,我很高兴丢失了一些信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-20
  • 1970-01-01
  • 2013-05-24
  • 1970-01-01
  • 2014-10-23
  • 1970-01-01
  • 2016-09-12
相关资源
最近更新 更多