Re: Monster memory leak and I can't figure out why
Re: Monster memory leak and I can't figure out why
- Subject: Re: Monster memory leak and I can't figure out why
- From: Ken Tozier <email@hidden>
- Date: Wed, 2 Jun 2010 09:51:06 -0400
Thanks all for the replies
Re point #1: I was using Activity Monitor and both the "Real Memory"
and "Virtual Memory" columns showed this 100+ MB leak every 5-10
seconds. After a minute or so of running, My app had gobbled up almost
2 gigs of memory.
Re point #2: All the thumbnail conversion code is contained within
this one method, so once it enters the loop, it doesn't exit till it's
done.
I tried using [[NSGarbageCollector defaultCollector]
collectExhaustively], as Jonathan suggested, tried [image
setCacheMode: NSImageCacheNever], but neither of those slowed the
ferocious gobbling of memory.
I finally resorted to using CGxxx functions and the problem
disappeared. My App now hums along generating 12 to 15 thumbnails per
second with a memory footprint in the 20 to 30 MB range. Here's what
worked:
- (NSString *) createJPEGThumbnail:(NSString *) inPath
site:(NSString *) inSite
{
NSDictionary *siteRecord,
*pubRecord;
NSString *sourceName = [inPath lastPathComponent],
*sourceRoot = [sourceName stringByDeletingPathExtension],
*destName = [[sourceRoot
stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]
stringByAppendingPathExtension: @"jpg"],
*pubCode = [self pubCodeFromPath: inPath],
*thumbPath;
NSFileManager *manager = [NSFileManager defaultManager];
siteRecord = [thumbDirectories objectForKey: inSite];
pubRecord = [[siteRecord objectForKey: @"publications"]
objectForKey: pubCode];
if (pubRecord == nil)
pubRecord = [[siteRecord objectForKey: @"publications"]
objectForKey: @"~MISCELLANEOUS"];
thumbPath = [[pubRecord objectForKey: @"thumb_path"]
stringByAppendingPathComponent: destName];
if (![manager fileExistsAtPath: thumbPath])
{
NSURL *sourceURL = [NSURL fileURLWithPath: inPath],
*destURL = [NSURL fileURLWithPath: thumbPath];
NSString *imageType = UtilPreferredUTIForFile(inPath);
NSNumber *maxPixels = [NSNumber numberWithInt: maxDimension];
NSDictionary *sourceOptions = [NSDictionary
dictionaryWithObjectsAndKeys:
imageType, kCGImageSourceTypeIdentifierHint,
kCFBooleanFalse, kCGImageSourceShouldCache,
kCFBooleanTrue,
kCGImageSourceCreateThumbnailFromImageAlways,
maxPixels, kCGImageSourceThumbnailMaxPixelSize,
nil];
CGImageSourceRef imageSourceCG =
CGImageSourceCreateWithURL((CFURLRef) sourceURL, (CFDictionaryRef)
sourceOptions );
if (imageSourceCG != NULL)
{
NSDictionary *imageProps = (NSDictionary *)
CGImageSourceCopyPropertiesAtIndex(imageSourceCG, 0, NULL);
int w = [[imageProps objectForKey: @"PixelWidth"] intValue],
h = [[imageProps objectForKey: @"PixelHeight"] intValue];
NSRect thumbRect = [self thumbRectWithSize: NSMakeSize(w, h)];
NSDictionary *destOptions = [NSDictionary
dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt: thumbRect.size.width],
kCGImagePropertyPixelWidth,
[NSNumber numberWithInt: thumbRect.size.height],
kCGImagePropertyPixelHeight,
nil];
CGImageRef imageRefCG =
CGImageSourceCreateThumbnailAtIndex(imageSourceCG, 0,
(CFDictionaryRef) sourceOptions);
if (imageRefCG != NULL)
{
CGImageDestinationRef destRef =
CGImageDestinationCreateWithURL((CFURLRef) destURL, kUTTypeJPEG, 1,
NULL);
if (destRef != NULL)
{
CGImageDestinationAddImage(destRef, imageRefCG, (CFDictionaryRef)
destOptions);
CGImageDestinationFinalize(destRef);
CFRelease(destRef);
}
CFRelease(imageRefCG);
}
CFRelease(imageSourceCG);
}
}
// make sure it worked
if ([manager fileExistsAtPath: thumbPath])
return thumbPath;
else
return nil;
}
On Jun 1, 2010, at 6:47 PM, Tony Romano wrote:
Hi Ken,
This code by itself should not be causing a leak. Couple of
questions:
1. How do you know you have a memory leak? Sound like a silly
question but you didn't tell us anything about what you are using to
detect leaks.
2. Who is calling this code, how many times? If you are passing
the image to something else in the sections you have commented out
and you are calling this many times, your memory usage may grow
senza any cache'ing that maybe happening.
I would suggest putting a NSLog statement at the beginning and look
at your output window to make sure the code is not called more than
you think.
-Tony Romano
On May 31, 2010, at 6:41 PM, Ken Tozier wrote:
Hi
I'm trying to write a thumbnailer class that takes a path to a
photo and creates a thumbnail at a user specified size. The code
creates the thumbnails OK, but there's this monster memory leak, to
the tune of about 100 MB every 3-4 seconds, that seems to be
related to NSImage.
What's happening is that if I comment out the line that initializes
a new image, the memory leak disappears. I've tried forcibly
releasing the images, tried autoreleasing them, tried creating a
fixed size buffer into which all the images are read, nothing seems
to work.
I'm using garbage collection, so that along with the deliberate
releasing of the images, makes me wonder why the collector isn't
getting the hint, that it's ok to release the memory for these
photos. Could someone point out what I'm doing in the following
code that prevents the images from getting released?
Thanks for any help
- (NSString *) createJPEGThumbnail:(NSString *) inPath
site:(NSString *) inSite
{
NSDictionary *siteRecord,
*pubRecord;
NSString *sourceName = [inPath lastPathComponent],
*sourceRoot = [sourceName stringByDeletingPathExtension],
*destName = [[sourceRoot
stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]
stringByAppendingPathExtension: @"jpg"],
*pubCode = [self pubCodeFromPath: inPath],
*thumbPath;
NSFileManager *manager = [NSFileManager defaultManager];
siteRecord = [thumbDirectories objectForKey: inSite];
pubRecord = [[siteRecord objectForKey: @"publications"]
objectForKey: pubCode];
if (pubRecord == nil)
pubRecord = [[siteRecord objectForKey: @"publications"]
objectForKey: @"~MISCELLANEOUS"];
thumbPath = [[pubRecord objectForKey: @"thumb_path"]
stringByAppendingPathComponent: destName];
if (![manager fileExistsAtPath: thumbPath])
{
// I've tried both of these, didn't make the slightest difference.
// Both leaked memory at a furious pace
// Option 1:
NSImage *image = [[[NSImage alloc] initWithContentsOfFile:
inPath] autorelease];
/* do some stuff */
// Option 2
NSImage *image = [[NSImage alloc] initWithContentsOfFile:
inPath];
/* do some stuff */
[image release];
}
// make sure it worked
if ([manager fileExistsAtPath: thumbPath])
return thumbPath;
else
return nil;
}
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
@hotmail.com
This email sent to email@hidden
-Tony
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden