Re: Losing my memory - a caching problem?
Re: Losing my memory - a caching problem?
- Subject: Re: Losing my memory - a caching problem?
- From: Ken Ferry <email@hidden>
- Date: Tue, 17 Aug 2010 10:05:46 -0700
Hi Stuart,
Just a couple of quick notes:
(1) I would focus your attention on CoreImage in this case.
(2) It is wonderful that you realized that if you want the bits in a
specific pixel format then you need to draw them in a bitmap, but you now
have a redundant bitmap:
NSBitmapImageRep *inBmpImgRep = [[[NSBitmapImageRep alloc]
> initWithCIImage:ciImage] autorelease];
NSInteger pixelsWide = [inBmpImgRep size].width;
NSInteger pixelsHigh = [inBmpImgRep size].height;
NSInteger samplesPerPixel = 4;
NSBitmapImageRep *bmpImgRep = [[[NSBitmapImageRep alloc]
> initWithBitmapDataPlanes:NULL
pixelsWide:pixelsWide pixelsHigh:pixelsHigh
> bitsPerSample:8
samplesPerPixel:samplesPerPixel
> hasAlpha:YES isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
> bitmapFormat:0
bytesPerRow:0 bitsPerPixel:0] autorelease];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:[NSGraphicsContext
> graphicsContextWithBitmapImageRep:bmpImgRep]];
[inBmpImgRep draw];
[NSGraphicsContext restoreGraphicsState];
You can directly draw the CIImage in the context created from the bitmap.
This by itself is not likely to be your problem, but fixing this may have a
side effect that fixes the problem. When you use -[NSBitmapImageRep
initWithCIImage:], it basically calls -[CIContext createCGImage:fromRect:]
using -[NSGraphicsContext CIContext]. The latter is possibly a long lived
object, and the CIContext may be the location of caches.
(Also, it's unlikely that you want device RGB as the colorspace for the
bitmap. If you want your results to be independent of the machine they're
produced on, you need to be using device-independent colorspaces.)
-Ken
On Tue, Aug 17, 2010 at 3:10 AM, Stuart Rogers <email@hidden> wrote:
> I'm having enormous difficulty keeping tabs on memory usage in my current
> project. I'm happy that I'm not leaking anything - Build & Analyse reports
> no
> issues, and neither does Instruments (Object Allocations and Leaks). And
> yet,
> when watching bulk memory usage I see my free RAM dropping like a stone
> (at the expense of my inactive RAM) and within seconds it has chewed
> through
> 8GB and starts kicking off extra page files. The active RAM usage is
> fairly
> modest, and nearer to what I would expect.
>
> My app is a neural network that uses signature data based upon image files.
> The above symptoms are most apparent during the testing phase, which
> consists of the following, repeated for several thousand image files:
> 1. Read in an image from file (720x576px)
> 2. Create a signature from the image (~7kB)
> 3. Discard the image
> 4. Apply the signature to the network.
>
> If I doctor my code to repeatedly use the same image file then the problem
> doesn't arise, which suggests to me that my code is fine but that the
> system
> is aggressively caching image data. Image caching is not welcome on this
> occasion - I use each image file once only.
>
> Any suggestions on how to tame this beast would be extremely welcome.
>
> Here's the code I use to read in my images (error handling snipped for
> clarity):
>
> - (ImageSignature *)signatureForPath:(NSString *)path
> {
> ImageSignature *sig = nil;
> NSURL *url = [NSURL fileURLWithPath:path];
> NSDictionary *opts = [NSDictionary
> dictionaryWithObject:(id)kCFBooleanFalse
>
> forKey:(NSString*)kCGImageSourceShouldCache];
> CGImageSourceRef src =
> CGImageSourceCreateWithURL((CFURLRef)url,(CFDictionaryRef)opts);
> if (src)
> {
> CGImageRef img =
> CGImageSourceCreateImageAtIndex(src,0,(CFDictionaryRef)opts);
> CFRelease(src);
> if (img)
> {
> sig = [self signatureForImage:img];
> CGImageRelease(img);
> }
> }
> return sig;
> }
>
> // Here's the signature creation code...
>
> - (ImageSignature*)signatureForImage:(CGImageRef)img
> {
> // Create a CIImage by passing the image through our filter chain.
> CIImage *ciImage = [self filteredImage:(CGImageRef)img];
>
> // Create a bitmap and paint our CIImage into it.
> NSBitmapImageRep *inBmpImgRep = [[[NSBitmapImageRep alloc]
> initWithCIImage:ciImage] autorelease];
> NSInteger pixelsWide = [inBmpImgRep size].width;
> NSInteger pixelsHigh = [inBmpImgRep size].height;
> NSInteger samplesPerPixel = 4;
> NSBitmapImageRep *bmpImgRep = [[[NSBitmapImageRep alloc]
> initWithBitmapDataPlanes:NULL
> pixelsWide:pixelsWide
> pixelsHigh:pixelsHigh bitsPerSample:8
> samplesPerPixel:samplesPerPixel
> hasAlpha:YES isPlanar:NO
> colorSpaceName:NSDeviceRGBColorSpace
> bitmapFormat:0
> bytesPerRow:0 bitsPerPixel:0]
> autorelease];
> [NSGraphicsContext saveGraphicsState];
> [NSGraphicsContext setCurrentContext:[NSGraphicsContext
> graphicsContextWithBitmapImageRep:bmpImgRep]];
> [inBmpImgRep draw];
> [NSGraphicsContext restoreGraphicsState];
>
> // Create an ImageSignature and paint our bitmap into it.
> ImageSignature *sig = [[[ImageSignature alloc] initWithSize:[bmpImgRep
> size]] autorelease];
> float *buffer = [sig allItems];
>
> // Signature creation snipped - it's a simple mapping of pixels to a
> float array
>
> return sig;
> }
>
> // The images are pre-processed via some CIFilters...
>
> - (CIImage *)filteredImage:(CGImageRef)img
> {
> // This method takes a CGImage and creates a filtered/scaled CIImage
> from it.
> NSInteger srcWide = CGImageGetWidth(img);
> NSInteger srcHigh = CGImageGetHeight(img);
> CIImage *ciImage = [CIImage imageWithCGImage:(CGImageRef)img];
>
> // Blur the image to smooth out the repeating noise from electronic
> interference.
> CIFilter *discBlur = [CIFilter filterWithName:@"CIDiscBlur"];
> [discBlur setDefaults];
> [discBlur setValue:ciImage forKey:@"inputImage"];
> [discBlur setValue:[NSNumber numberWithFloat:blurRadius] forKey:@
> "inputRadius"];
> ciImage = [discBlur valueForKey:@"outputImage"];
>
> // Other filters (scaling, edge detection, etc) snipped...
>
> // We don't need pixels around the periphery, crop it.
> CIFilter *cropROI = [CIFilter filterWithName:@"CICrop"];
> [cropROI setDefaults];
> [cropROI setValue:ciImage forKey:@"inputImage"];
> CIVector *roiVector = [CIVector vectorWithX:roi.origin.x Y:roi.origin.y
> Z:roi.size.width W:roi.size.height];
> [cropROI setValue:roiVector forKey:@"inputRectangle"];
> ciImage = [cropROI valueForKey:@"outputImage"];
>
> return ciImage;
> }
>
> Have I set up my caching policy (kCGImageSourceShouldCache) incorrectly?
> I tried supplying a BOOL wrapped in an NSNumber but that made no
> difference.
>
> This project is for Mac OS X 10.6 - I have no need to support anything
> earlier.
>
> Stuart
> _______________________________________________
>
> 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
>
_______________________________________________
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