Iphone and malloc memory leaks?

Ok, so I finally got to the point where I test my iPad app on a real iPad ...

One thing my app does is display a large (2MB) image in scroll mode. This causes the iPad to receive memory alerts. I run my application in tools to check for a leak.

When I load the image, a leak is detected and I see the following in the distribution:

ALl Allocation: 83.9 MB Malloc 48.55 MB: 48.55 MB Malloc 34.63 MB: 34.63 MB

What I'm trying to figure out is how to properly plug the leak, but also why a 2MB image is causing a 20x malloc

I am very new to programming in obj-c, so I'm sure this is an obvious thing, but I just can't figure it out. Here is the code:

@interface ChartsViewController : UIViewController <UIScrollViewDelegate, UIPickerViewDelegate, UIPickerViewDataSource> {
    IBOutlet UIScrollView *scrollView;
    UIImageView *imageView;
    NSString *chart;
    NSString *chartFile;
    UIPickerView *picker;
    NSDictionary *chartsDictionary;
    NSArray *chartTypes;
    NSArray *charts;
    IBOutlet UILabel *chartNameLabel;
    IBOutlet UIActivityIndicatorView *activityIndicator;



}

@property (nonatomic, retain) UIScrollView *scrollView;
@property (nonatomic, retain) UIImageView *imageView;
@property (nonatomic, retain) NSString *chart;
@property (nonatomic, retain) NSString *chartFile;
@property (nonatomic, retain) IBOutlet UIPickerView *picker;
@property (nonatomic, retain) NSDictionary *chartsDictionary;
@property (nonatomic, retain) NSArray *chartTypes;
@property (nonatomic, retain) NSArray *charts;
@property (nonatomic, retain) IBOutlet UILabel *chartNameLabel;
@property (nonatomic, retain) IBOutlet UIActivityIndicatorView *activityIndicator;


-(IBAction) chartSelected;
- (void)alertView:(UIAlertView *)actionSheet 

      

///////////////////////////////

-(IBAction) chartSelected {
    [imageView removeFromSuperview];
    imageView = nil;
    chartNameLabel.text = @"";

    NSInteger chartTypeRow = [picker selectedRowInComponent:kChartTypeComponent];
    NSInteger chartRow= [picker selectedRowInComponent:kChartComponent];
    chart = [self.charts objectAtIndex:chartRow];
    chartFile = [chart stringByReplacingOccurrencesOfString:@" " withString:@"_"];


    NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
                                                         NSUserDomainMask, YES);


    NSString *docsPath = [paths objectAtIndex:0];
    NSString *tempString = [[NSString alloc]initWithFormat:@"%@/%@.jpg",docsPath,chartFile];




    NSData *temp = [NSData dataWithContentsOfFile:tempString];

    if (temp != NULL){

        temp = nil;
        [imageView removeFromSuperview];
        imageView = nil;

        UIImageView *tempImage = [[UIImageView alloc]initWithImage:[UIImage imageWithContentsOfFile: tempString]];
        [tempString release];
        self.imageView = tempImage;


        scrollView.contentSize = CGSizeMake(imageView.frame.size.width , imageView.frame.size.height);
        scrollView.maximumZoomScale = 4.0;
        scrollView.minimumZoomScale = .05;
        scrollView.clipsToBounds = YES;
        scrollView.delegate = self;
        scrollView.zoomScale = .3;

        [scrollView addSubview:imageView];
        [tempImage release];
        imageView = nil;
        chartNameLabel.text = chart;

    }

    else {

        UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Download Chart" 
                                                       message:@"It appears that you have not yet downloaded this chart. Press OK to download this chart to your iPad. Depending on your internet connection, the download could take several minutes." 
                                                      delegate:self 
                                             cancelButtonTitle:@"OK" 
                                             otherButtonTitles:@"Cancel", nil];
        [alert show];
        [alert release];

    }

    }

- (void)dealloc {

    [imageView release];
    [scrollView release];
    [chartsDictionary release];
    [picker release];
    [chartTypes release];
    [charts release];
    [super dealloc];
}

      

+2


a source to share


5 answers


tempImage is still leaking.

replace the line that says

imageView = nil;

      

from



[self setImageView: nil];

      

or

self.imageView = nil;

      

+2


a source


You say you have 2MB of the image. But that means 2MB JPG, right?

So what is the size in pixels - because when you load an image into memory it needs to be compressed. And that means it will horizontal resolution * vertical resolution * 8 * 4 (alpha channel) bytes in memory

.



This is why you are looking at 20-30 MB every time you upload an image, regardless of persistence issues (which only means that every 30 MB allocated will not be released).

+3


a source


Lots of leaks in this code.

For every object created with alloc

, you need to release it at some point when you finish using it.

The following items are leaking and must be released

  • tempString

  • tempImage

  • alert

Also, you don't need to NSAutoreleasePool

have one created for you using the cocoa structure before the event that raises yours is fired IBAction

and exhausted with the method completing. In addition, the autocomplete pool is also only responsible for the items that have been placed in it, including everything you post a message autorelease

and any objects you return from a method other than alloc

, new

or one with copy

in the header.

Also, be aware that setting a local variable to nil is not the same as releasing it.

For example, the image creation should be

UIImageView *tempImage = [[UIImageView alloc]initWithImage:[UIImage imageWithContentsOfFile: tempString]];
self.imageView = tempImage;
[tempImage release];

      

Edit:

One more thing. When you access imageview

without using self.imageview

, you are accessing the ivar directly and not through a property. So when you do self.imageview = tempImage

, it keeps the image representation as it should, but when you do imageview = nil

, it outputs the link without freeing memory. This is another leak. Try it instead self.imageview = nil

.

As for so much memory, I don't know if it has nothing to do with expanding the image to its full size (pixel by pixel) and not its compressed jpg size or other data leaks along with the UIImageView object.

+2


a source


Both the following lines will keep the UIImageView highlighted as tempImage.

self.imageView = tempImage;
[scrollView addSubview:imageView];

      

add this line after addSubview:

[tempImage release];

      

You don't need an image element as a member unless you manipulate it later. If you save it, be sure to release it in dealloc. In general, every property marked as retained should be released in dealloc unless you have a specific reason not to.

I usually don't make properties or even have members for views that will live in the view hierarchy, unless I need to manipulate them, such as changing the text of the UILabel or the state of the UIButton.

0


a source


It would be nice to switch to ARC. Alternatively, create a static analyzer and fix any warnings it gives you. It's not bad.

It seems that you sometimes use imageView and sometimes self.imageView. This indicates that your instance variable is imageView and not _imageView. This is a huge source of error. If imageView is a property (release), self.imageView = nil releases it, but imageView = nil doesn't. I highly recommend starting all instance variables with an underscore so that you only refer to them on purpose.

0


a source







All Articles