如何修复 CFRuntimeCreateInstance 对象泄漏?

发布于 2024-11-28 17:30:21 字数 2612 浏览 0 评论 0原文

使用仪器泄漏工具分析我的应用程序时,我遇到了看不见的对象泄漏(CFRuntimeCreateInstance)。我对泄漏发生的地方有粗略的想象,但无法发现它:)调用树将我指向从精灵表加载图像的类方法。下面是调用树的一个片段(直到泄漏对象 CFRuntimeCreateInstance):

+[ImageCache loadImageOfType:andIndex:]
 +[NSString stringWithFormat:]
  _CFStringCreateWithFormatAndArgumentsAux
   CFStringCreateCopy
    __CFStringCreateImmutableFunnel3
     _CFRuntimeCreateInstance

我正在使用这个辅助类方法来加载和缓存图像。该方法使用静态 NSMutableDictionary 来推送加载的图像以供进一步使用。我的图像被分组到精灵表中,因此该方法读取相应的图像文件并读取相应的图像区域。这是我的方法:

+(UIImage*)loadImageOfType:(int)type andIndex:(int)index{
  UIImage *image;

  if (!dict) dict = [[NSMutableDictionary dictionary] retain];

  //First, trying to get already loaded image
  int ind = IMAGECOUNT * type + index; //calculating the index that is used for storing image in dict
  image = [dict objectForKey:[NSString stringWithFormat:@"%d", ind]]; //trying to get image
  if (!image){ //if image is not loaded then read the spriteimage file 
    NSString *spritesheetName = [NSString stringWithFormat:@"itemsprite%d.png", type];
    NSString* imagePath = [[NSBundle mainBundle] pathForResource:spritesheetName ofType:nil];
    image = [UIImage imageWithContentsOfFile:imagePath];
    if (image) //if spritesheet exists
    {
        int loopInd; 
        CGFloat x = 0, y = 0;
        //load all images from it
        for (int i=0; i<IMAGECOUNT; i++) {
            UIImage *img;
            loopInd = IMAGECOUNT * type + i;
            CGImageRef imageRef = CGImageCreateWithImageInRect( [image CGImage], CGRectMake(x, y, ITEMIMAGESIZE, ITEMIMAGESIZE)); 
            img = [UIImage imageWithCGImage:imageRef];
            [dict setObject:img forKey:[NSString stringWithFormat:@"%d", loopInd]];
            CGImageRelease(imageRef);
            x += ITEMIMAGESIZE;
        }
    }
    //set image var to be image needed
    image = [dict objectForKey:[NSString stringWithFormat:@"%d", ind]];
  }    

  return image;   
}

有什么建议,从哪里开始?

更新:我在调试区域也有很多消息,所有消息都非常相似:

__NSAutoreleaseNoPool(): Object 0x4c55e80 of class NSCFNumber autoreleased with no pool in place - just leaking

__NSAutoreleaseNoPool(): Object 0x4c69060 of class __NSCFDictionary autoreleased with no pool in place - just leaking

__NSAutoreleaseNoPool(): Object 0x4c6a620 of class NSCFString autoreleased with no pool in place - just leaking

__NSAutoreleaseNoPool(): Object 0x4e75fe0 of class NSPathStore2 autoreleased with no pool in place - just leaking

__NSAutoreleaseNoPool(): Object 0x4e312d0 of class UIImage autoreleased with no pool in place - just leaking

I'm having unseen object leak (CFRuntimeCreateInstance) when profiling my app with instrument leak tool. I have rough imagination where the leak occurs but unable to spot it :) The call tree points me to my class method for loading an image from a spritesheet. Here is a fragment of the call tree (until leaking object CFRuntimeCreateInstance):

+[ImageCache loadImageOfType:andIndex:]
 +[NSString stringWithFormat:]
  _CFStringCreateWithFormatAndArgumentsAux
   CFStringCreateCopy
    __CFStringCreateImmutableFunnel3
     _CFRuntimeCreateInstance

I'm using this helper class method for loading and caching the image. The method uses static NSMutableDictionary where it pushes loaded image for further use. My images are grouped into spritesheets, so the method reads corresponding image file and reads corresponding image area. Here is my method:

+(UIImage*)loadImageOfType:(int)type andIndex:(int)index{
  UIImage *image;

  if (!dict) dict = [[NSMutableDictionary dictionary] retain];

  //First, trying to get already loaded image
  int ind = IMAGECOUNT * type + index; //calculating the index that is used for storing image in dict
  image = [dict objectForKey:[NSString stringWithFormat:@"%d", ind]]; //trying to get image
  if (!image){ //if image is not loaded then read the spriteimage file 
    NSString *spritesheetName = [NSString stringWithFormat:@"itemsprite%d.png", type];
    NSString* imagePath = [[NSBundle mainBundle] pathForResource:spritesheetName ofType:nil];
    image = [UIImage imageWithContentsOfFile:imagePath];
    if (image) //if spritesheet exists
    {
        int loopInd; 
        CGFloat x = 0, y = 0;
        //load all images from it
        for (int i=0; i<IMAGECOUNT; i++) {
            UIImage *img;
            loopInd = IMAGECOUNT * type + i;
            CGImageRef imageRef = CGImageCreateWithImageInRect( [image CGImage], CGRectMake(x, y, ITEMIMAGESIZE, ITEMIMAGESIZE)); 
            img = [UIImage imageWithCGImage:imageRef];
            [dict setObject:img forKey:[NSString stringWithFormat:@"%d", loopInd]];
            CGImageRelease(imageRef);
            x += ITEMIMAGESIZE;
        }
    }
    //set image var to be image needed
    image = [dict objectForKey:[NSString stringWithFormat:@"%d", ind]];
  }    

  return image;   
}

Any suggestions, where to start?

UPDATE: I'm also having a lot of messages in debug area, all are quite similar:

__NSAutoreleaseNoPool(): Object 0x4c55e80 of class NSCFNumber autoreleased with no pool in place - just leaking

__NSAutoreleaseNoPool(): Object 0x4c69060 of class __NSCFDictionary autoreleased with no pool in place - just leaking

__NSAutoreleaseNoPool(): Object 0x4c6a620 of class NSCFString autoreleased with no pool in place - just leaking

__NSAutoreleaseNoPool(): Object 0x4e75fe0 of class NSPathStore2 autoreleased with no pool in place - just leaking

__NSAutoreleaseNoPool(): Object 0x4e312d0 of class UIImage autoreleased with no pool in place - just leaking

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

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

发布评论

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

评论(2

病女 2024-12-05 17:30:22

我发现了问题。在游戏开始时,我会预加载图像。我有一个方法“loadGameResourses”,它循环并对单个图像加载方法“loadImageOfType...”进行多次调用。现在,我正在单独的线程中执行“loadGameResourses”的调用:

[self performSelectorInBackground:@selector(loadGameResourses) withObject:nil]; 

当我将其替换为:我听说你需要在主线程中处理 UIKit 的东西时,泄漏就消失了

[self loadGameResourses];

,所以看起来我已经选择了使用这种适当的方法时,一切都会按预期进行:

[self performSelectorOnMainThread: @selector(loadGameResourses) withObject:nil waitUntilDone: NO]; 

I found the problem. At the beginning of the game, I'm preloading the images. I have a method "loadGameResourses" that loops and does multiple calls to single image loading method "loadImageOfType...". Now, I'm performing the call of ""loadGameResourses" in separate thread:

[self performSelectorInBackground:@selector(loadGameResourses) withObject:nil]; 

The leaks just disappeared when I replaced that with:

[self loadGameResourses];

I heard that you need to deal with UIKit stuff in the main thread, so it looks like I have picked the wrong method. Everything works as expected when using this appropriate method:

[self performSelectorOnMainThread: @selector(loadGameResourses) withObject:nil waitUntilDone: NO]; 
后来的我们 2024-12-05 17:30:22

我听说仪器的泄漏工具可以报告错误的泄漏。您是否尝试过在应用程序运行时打开活动监视器并观察内存?如果存在泄漏,内存量就会不断变大。在挖得太深之前确保确实有泄漏。

I have heard that the instrument's leak tool can report false leaks. Have you tried opening Activity Monitor while your app is running and watching the memory? If there is a leak, the amount of memory will keep getting larger and larger. Make sure you actually have a leak before you dig too deep.

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