2010-04-23 98 views
2

好吧,我终于到了测试我的iPad应用程序的地步......iphone内存泄漏和malloc?

我的应用程序所做的一件事是在滚动视图中显示一个大的(2mb)图像。这导致iPad获得内存警告。我在仪器中运行应用程序来检查泄漏。

当我加载图像,检测到泄漏,我看到的分配执行以下操作:

所有分配:83.9 MB malloc的48.55 MB:48.55 MB malloc的34.63 MB:34.63 MB

什么即时通讯试图了解如何明显堵塞泄漏,但也为什么一个2MB的图像导致一个20x大小的malloc

我是非常新的obj-c编程,所以我确信这是一个明显的事情,但我不知道。下面是代码:

@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]; 
} 
+0

缺少代码。 – 2010-04-23 04:42:18

+0

你很快:)它现在有 – Brodie 2010-04-23 04:44:27

+0

任何人都可以解释为什么它为2-3 MB图像分配20-30 MB? – Brodie 2010-04-23 05:09:47

回答

2

tempImage仍在泄漏。

替换这行

imageView = nil; 

[self setImageView: nil]; 

self.imageView = nil; 
2

此代码中有大量泄漏。

对于使用alloc创建的每个对象,您需要在完成使用时释放它。

以下项目被泄露,并需要被释放

  1. tempString
  2. tempImage
  3. alert

而且,你不需要那么NSAutoreleasePool,为创建一个你在调用你的IBAction的事件之前由可可框架调用,并用方法fin ishes。此外,自动释放池也仅负责放入其中的项目,其中包括您发送autorelease消息的任何内容以及标题中使用alloc,newcopy之外的方法取回的任何对象。

此外,知道将局部变量设置为零与释放它不同。

例如,创建形象应该是

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

编辑:

一两件事。当您在不使用self.imageview的情况下访问imageview时,您直接访问伊娃而不是通过该媒体资源。因此,当您执行self.imageview = tempImage时,它会保留图像视图,但是当您执行imageview = nil时,它会在不释放内存的情况下将参考删除。这是另一个泄漏。改为尝试self.imageview = nil。至于为什么它有这么多的内存,除非它涉及将图像扩展为全尺寸(按像素),而不是其压缩的jpg大小,或者与其他数据一起泄漏,否则我不知道UIImageView对象。

+0

我更改了代码并编辑了上面的代码,但问题没有改变。 – Brodie 2010-04-23 05:07:20

+0

编辑我的答案包括另一个泄漏。 – 2010-04-23 05:15:15

0

以下两行都将保留作为tempImage分配的UIImageView。

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

加入这一行addSubview后:

[tempImage release]; 

,除非你在后面操纵它你不需要的ImageView作为成员。如果你保留它,一定要在dealloc中释放它。一般来说,每个标记为保留的财产应该在dealloc中释放,除非您有某些不具备的特定原因。

我通常不会生成属性,甚至没有成员的视图将生活在视图层次中,除非我需要操纵它们,例如更改UILabel的文本或UIButton的状态。

+0

我编辑了我的代码,并且还包含了我的dealloc方法。但问题并没有改变。这是说我有20-30 MB分配,然后每次我加载一个新的图表,它增加了另一个20-30 MB – Brodie 2010-04-23 05:08:29

3

你说你有一个2MB的图像。但是,这意味着一个2MB的JPG,对吗?

那么以像素为单位的大小是多少 - 因为当你将图像加载到内存中时,它必须被解压缩。这意味着它将是horizontal resolution * vertical resolution * 8 * 4 (alpha channel) bytes in memory

这就是为什么你看到每次你加载图像20-30MB分配,而不管保留问题(这意味着每个30MB分配将不会被释放)。

+0

很好的解释,谢谢 – Brodie 2010-04-23 13:26:20

0

将切换到ARC是一个好主意。或者,使用静态分析器进行构建并修复它提供的所有警告。这很好。

看来,你有时使用imageView有时使用self.imageView。这表明你的实例变量是imageView而不是_imageView。这是一个巨大的错误来源。如果imageView是(释放)属性,self.imageView = nil释放它,但imageView = nil不释放。我强烈建议使用下划线启动所有实例变量,以便您只有故意访问它们。