views:

395

answers:

1

I'm building an app that has several different sections to it, all of which are pretty image-heavy. It ties in with my client's website and they're a "high-design" type outfit.

One piece of the app is images uploaded from the camera or the library, and a tableview that shows a grid of thumbnails. Pretty reliably, when I'm dealing with the camera version of UIImagePickerControl, I get hit for low memory. If I bounce around that part of the app for a while, I occasionally and non-repeatably crash with "status:10 (SIGBUS)" in the debugger.

On low memory warning, my root view controller for that aspect of the app goes to my data management singleton, cruises through the arrays of cached data, and kills the biggest piece, the image associated with each entry. Thusly:

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Low Memory Warning"
                                                    message:@"Cleaning out events data"
                                                   delegate:nil
                                          cancelButtonTitle:@"All right then."
                                          otherButtonTitles:nil];
    [alert show];
    [alert release];

    NSInteger spaceSaved;

    DataManager *data = [DataManager sharedDataManager];
    for (Event *event in data.eventList) {
        spaceSaved += [(NSData *)UIImagePNGRepresentation(event.image) length];
        event.image = nil;
        spaceSaved -= [(NSData *)UIImagePNGRepresentation(event.image) length];
    }

    NSString *titleString = [NSString stringWithFormat:@"Saved %d on event images", spaceSaved];

    for (WondrMark *mark in data.wondrMarks) {
        spaceSaved += [(NSData *)UIImagePNGRepresentation(mark.image) length];
        mark.image = nil;
        spaceSaved -= [(NSData *)UIImagePNGRepresentation(mark.image) length];
    }

    NSString *messageString = [NSString stringWithFormat:@"And total %d on event and mark images", spaceSaved];

    NSLog(@"%@ - %@", titleString, messageString);

    // Relinquish ownership any cached data, images, etc that aren't in use.
}

As you can see, I'm making a (poor) attempt to eyeball the memory space I'm freeing up. I know it's not telling me about the actual memory footprint of the UIImages themselves, but it gives me SOME numbers at least, so I can see that SOMETHING'S happening. (Sorry for the hamfisted way I build that NSLog message too--I was going to fire another UIAlertView, but realized it'd be more useful to log it.)

Pretty reliably, after toodling around in the image portion of the app for a while, I'll pull up the camera interface and get the low memory UIAlertView like three or four times in quick succession. Here's the NSLog output from the last time I saw it:

2010-05-27 08:55:02.659 EverWondr[7974:207] Saved 109591 on event images - And total 1419756 on event and mark images
wait_fences: failed to receive reply: 10004003
2010-05-27 08:55:08.759 EverWondr[7974:207] Saved 4 on event images - And total 392695 on event and mark images
2010-05-27 08:55:14.865 EverWondr[7974:207] Saved 4 on event images - And total 873419 on event and mark images
2010-05-27 08:55:14.969 EverWondr[7974:207] Saved 4 on event images - And total 4 on event and mark images
2010-05-27 08:55:15.064 EverWondr[7974:207] Saved 4 on event images - And total 4 on event and mark images

And then pretty soon after that we get our SIGBUS exit. So that's the situation. Now my specific questions:

THE time I see this happening is when the UIPickerView's camera iris shuts. I click the button to take the picture, it does the "click" animation, and Instruments shows my memory footprint going from about 10mb to about 25mb, and sitting there until the image is delivered to my UIViewController, where usage drops back to 10 or 11mb again. If we make it through that without a memory warning, we're golden, but most likely we don't. Anything I can do to make that not be so expensive?

Second, I have NSZombies enabled. Am I understanding correctly that that's actually preventing memory from being freed? Am I subjecting my app to an unfair test environment?

Third, is there some way to programmatically get my memory usage? Or at least the usage for a UIImage object? I've scoured the docs and don't see anything about that.

+1  A: 
progrmr
My C is poor (and my Obj-C is only slightly better). I pasted that into my view controller, and got compilation errors on each line. Is there something I need to include or something?
Dan Ray
Sorry, you need to #import "mach/mach.h"
progrmr
I added a freeMemory() function as well. See above.
progrmr
Thanks. What is a "size_t"? Can I treat it like an int?
Dan Ray
Yes, size_t is usually an unsigned long or similar. Edit4 above shows how I log this info in my 1sec timer method, just to give you an idea. I hope this helps with your 3rd question.
progrmr
Certainly does. Thanks!
Dan Ray