问题
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
回答1:
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];
回答2:
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.
来源:https://stackoverflow.com/questions/7018329/how-to-fix-cfruntimecreateinstance-object-leak