图像创建函数中的内存泄漏

发布于 2024-07-22 03:30:18 字数 4802 浏览 0 评论 0原文

我目前正在开发一款 iPhone 游戏,需要即时创建一些动画。 动画基于多个图像,由于图像组合的范围太大并且不可能预先创建所有序列,因此我希望能够在每次情况发生变化时重新计算一组图像。

该函数创建一系列图像,用作动画序列。 我需要两件事上的帮助:

  1. 有几个大的内存泄漏,我无法找到 - 我需要帮助找到它们
  2. 由于我是 iPhone 新手,我想知道是否有更好的方法来做到这一点,如果您对如何编写有更好的建议,请分享...

代码:

(void) updateImages:(int) smallPicID
{
    CGRect smallPicRect;
    smallPicRect.size = CGSizeMake(25.0f, 25.0f);

    //TODO: add smallPic location for every image. Currently the values only match the first image...
    static const CGPoint smallPicLocation[11][SMALLPIC_LOCATION_COUNT] = 
    {
        { {126.0f, 153.0f},{105.0f, 176.0f}, {115.0f, 205.0f}, {145.0f, 211.0f}, {166.0f, 188.0f}, {156.0f, 159.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} }
    };

    for(int i = 0; i < self.m_finalImages.count; ++i)
    {
        // start with base image
        UIImage * baseImg = [self.m_finalImagesEmpty objectAtIndex:i];
        CGImageRef baseImgCtx = baseImg.CGImage;

        // Create the bitmap context that matches the baseImg parameters
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGContextRef newImgCtx = CGBitmapContextCreate(NULL, 
                                                       CGImageGetWidth(baseImgCtx), 
                                                       CGImageGetHeight(baseImgCtx), 
                                                       8, 0, colorSpace, 
                                                       (kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
        CGColorSpaceRelease(colorSpace); 

        if (newImgCtx == NULL) 
        { 
            // error creating context
            assert(0);
            return;
        }

        // Get empty drum image width, height.
        size_t w = CGImageGetWidth(baseImgCtx);
        size_t h = CGImageGetHeight(baseImgCtx);
        CGRect rect = {{0,0},{w,h}}; 

        // Draw the image to the bitmap context.
        // newImgCtx now contains the full empty drum image.
        CGContextDrawImage(newImgCtx, rect, baseImgCtx); 

        CGContextSaveGState(newImgCtx);
        // translate & scale because of origin difference between UIKit and CG
        CGContextTranslateCTM(newImgCtx, 0, h);
        CGContextScaleCTM(newImgCtx, 1, -1);

        int startLocation = 0;
        int endLocation = SMALLPIC_LOCATION_COUNT;

        // for each location
        for(int j = startLocation; j < endLocation; j++)
        {
            // if its empty, nothing to do, move to next bullet
            if (m_locationStatus[j] == CY_EMPTY)
                continue;

            UIImage * srcImg;
            switch (m_locationStatus[j]) 
            {
                case CY_FULL: srcImg = [self.m_finalImagesLoaded objectAtIndex:i];  break;
                case CY_USED:  srcImg = [self.m_finalImagesSpent objectAtIndex:i];  break;
            }

            // create small image containing only the smallpic from the src img
            smallPicRect.origin = smallPicLocation[i][j];
            CGImageRef smallpicCGImg = CGImageCreateWithImageInRect(srcImg.CGImage, smallPicRect);

            // draw the smallpic into the new context
            CGContextDrawImage(newImgCtx, smallPicRect, smallpicCGImg);         

            CGImageRelease(smallpicCGImg);
        }

        CGContextRestoreGState(newImgCtx);

        // update the image from the context
        UIImage *baseImg = [self.m_finalImages objectAtIndex:i];
        CGImageRef imgref = CGBitmapContextCreateImage(newImgCtx);
        //[baseImg release];
        [baseImg initWithCGImage:imgref];

        CGContextRelease(newImgCtx);
    }
}

I am currently working on an iPhone game, and need to create some animation on the fly. The animation is based on several images, and as the range of image combinations is too large and it is impossible to pre-create all of sequences, I'd like to be able to recalculate a set of images every time the situation changes.

The function creates a series of images, to be used as an animation sequence. I need help with two things:

  1. There are several large memory leaks that I'm having trouble finding - I need help locating them
  2. Since I'm new to the iPhone, I want to know if there is a better way to do it, if you have a better suggestion on how to write it, please share...

Code:

(void) updateImages:(int) smallPicID
{
    CGRect smallPicRect;
    smallPicRect.size = CGSizeMake(25.0f, 25.0f);

    //TODO: add smallPic location for every image. Currently the values only match the first image...
    static const CGPoint smallPicLocation[11][SMALLPIC_LOCATION_COUNT] = 
    {
        { {126.0f, 153.0f},{105.0f, 176.0f}, {115.0f, 205.0f}, {145.0f, 211.0f}, {166.0f, 188.0f}, {156.0f, 159.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} },
        { {183.0f, 91.0f}, {201.0f, 97.0f}, {205.0f, 115.0f}, {191.0f, 127.0f}, {173.0f, 122.0f}, {169.0f, 124.0f} }
    };

    for(int i = 0; i < self.m_finalImages.count; ++i)
    {
        // start with base image
        UIImage * baseImg = [self.m_finalImagesEmpty objectAtIndex:i];
        CGImageRef baseImgCtx = baseImg.CGImage;

        // Create the bitmap context that matches the baseImg parameters
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        CGContextRef newImgCtx = CGBitmapContextCreate(NULL, 
                                                       CGImageGetWidth(baseImgCtx), 
                                                       CGImageGetHeight(baseImgCtx), 
                                                       8, 0, colorSpace, 
                                                       (kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
        CGColorSpaceRelease(colorSpace); 

        if (newImgCtx == NULL) 
        { 
            // error creating context
            assert(0);
            return;
        }

        // Get empty drum image width, height.
        size_t w = CGImageGetWidth(baseImgCtx);
        size_t h = CGImageGetHeight(baseImgCtx);
        CGRect rect = {{0,0},{w,h}}; 

        // Draw the image to the bitmap context.
        // newImgCtx now contains the full empty drum image.
        CGContextDrawImage(newImgCtx, rect, baseImgCtx); 

        CGContextSaveGState(newImgCtx);
        // translate & scale because of origin difference between UIKit and CG
        CGContextTranslateCTM(newImgCtx, 0, h);
        CGContextScaleCTM(newImgCtx, 1, -1);

        int startLocation = 0;
        int endLocation = SMALLPIC_LOCATION_COUNT;

        // for each location
        for(int j = startLocation; j < endLocation; j++)
        {
            // if its empty, nothing to do, move to next bullet
            if (m_locationStatus[j] == CY_EMPTY)
                continue;

            UIImage * srcImg;
            switch (m_locationStatus[j]) 
            {
                case CY_FULL: srcImg = [self.m_finalImagesLoaded objectAtIndex:i];  break;
                case CY_USED:  srcImg = [self.m_finalImagesSpent objectAtIndex:i];  break;
            }

            // create small image containing only the smallpic from the src img
            smallPicRect.origin = smallPicLocation[i][j];
            CGImageRef smallpicCGImg = CGImageCreateWithImageInRect(srcImg.CGImage, smallPicRect);

            // draw the smallpic into the new context
            CGContextDrawImage(newImgCtx, smallPicRect, smallpicCGImg);         

            CGImageRelease(smallpicCGImg);
        }

        CGContextRestoreGState(newImgCtx);

        // update the image from the context
        UIImage *baseImg = [self.m_finalImages objectAtIndex:i];
        CGImageRef imgref = CGBitmapContextCreateImage(newImgCtx);
        //[baseImg release];
        [baseImg initWithCGImage:imgref];

        CGContextRelease(newImgCtx);
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

江湖彼岸 2024-07-29 03:30:18

首先引起我注意的是在接近尾部时使用 CGBitmapContextCreateImage() 创建 imgref,但没有匹配的 CGImageRelease(),以及 baseImg initWithCGImage: 消息除了消耗内存之外什么也不做。 我认为你想用以下内容替换以“从上下文更新图像”开头的部分:

CGImageRef imgref = CGBitmapContextCreateImage(newImgCtx);
UIImage *replacmentBaseImg = [[UIImage alloc] initWithCGImage:imgref];
CGImageRelease(imgref);

[self.m_finalImages replaceObjectAtIndex:i withObject:replacementBaseImg];
[replacementBaseImg release];

CGContextRelease(newImgCtx);

这假设 m_finalImages 是一个 NSMutableArray 并且你已经正确释放了已插入该数组中的其他图像,因此当你替换它们,它们就会被释放。

在更大的结构说明中,您可能希望考虑将较小的子图像绘制到单独的 CALayers 中,然后将这些图层在屏幕的不同位置进出,以完成动画。 Quartz 绘图的成本很高,而 CALayers 是作为纹理存储在 GPU 上的缓存图像。 其他人已经使用 CALayers 执行了这些基于精灵的动画,并取得了令人印象深刻的性能。

The first things that jump out at me are the creation of imgref near the end with a CGBitmapContextCreateImage(), but no matching CGImageRelease(), and the baseImg initWithCGImage: message that does nothing but chew up memory. I think you want to replace the section starting with "update the image from the context" with something like:

CGImageRef imgref = CGBitmapContextCreateImage(newImgCtx);
UIImage *replacmentBaseImg = [[UIImage alloc] initWithCGImage:imgref];
CGImageRelease(imgref);

[self.m_finalImages replaceObjectAtIndex:i withObject:replacementBaseImg];
[replacementBaseImg release];

CGContextRelease(newImgCtx);

This assumes that m_finalImages is an NSMutableArray and that you've properly released your other images that have been inserted in that array, so that when you replace them they get deallocated.

On a larger structural note, you may wish to look at drawing your smaller subimages into individual CALayers, and then swapping those layers in and out of the screen at the various locations to accomplish your animation. Quartz drawing is expensive, and CALayers are cached images stored as textures on the GPU. Other people have performed these sprite-based animations using CALayers and achieved impressive performance.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文