【问题标题】:iphone memory leaks and malloc?iphone内存泄漏和malloc?
【发布时间】:2010-04-23 04:40:37
【问题描述】:

好的,我终于可以在实际的 iPad 上测试我的 iPad 应用了...

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

当我加载图像时,检测到泄漏,我在分配中看到以下内容:

所有分配:83.9 MB Malloc 48.55 MB:48.55 MB Malloc 34.63 MB:34.63 MB

我想了解的是如何明显地堵住漏洞,以及为什么 2MB 的图像会导致 malloc 的大小是该大小的 20 倍

我对 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];
}

【问题讨论】:

  • 你的速度很快 :) 现在就在那里
  • 谁能解释为什么它为 2-3 MB 的图像分配 20-30 MB 的空间?

标签: iphone objective-c memory-leaks malloc


【解决方案1】:

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

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

这就是为什么您每次加载图像时都会看到分配了 20-30MB 的空间,而不管保留问题如何(这只是意味着不会释放每个分配的 30MB)。

【讨论】:

    【解决方案2】:

    tempImage 仍在泄漏。

    替换写着

    的行
    imageView = nil;
    

    [self setImageView: nil];
    

    self.imageView = nil;
    

    【讨论】:

      【解决方案3】:

      这段代码有很多漏洞。

      对于使用alloc 创建的每个对象,您需要在使用完毕后的某个时间点释放它。

      以下项目正在泄露,需要发布

      1. tempString
      2. tempImage
      3. alert

      另外,您不需要NSAutoreleasePool,它是由可可框架在调用您的IBAction 的事件被调用之前为您创建的,并随着方法完成而耗尽。此外,自动释放池也只对已放置在其中的项目负责,其中包括您向其发送 autorelease 消息的任何对象以及您从 allocnew 或其他方法以外的方法返回的任何对象标题中带有copy

      另外,要知道将局部变量设置为 nil 与释放它不同。

      例如创建图像应该是

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

      编辑:

      还有一件事。当您在不使用self.imageview 的情况下访问imageview 时,您是在直接访问ivar,而不是通过属性。因此,当您执行self.imageview = tempImage 时,它会保留应有的图像视图,但是当您执行imageview = nil 时,它会取消引用而不释放内存。这是另一个泄漏。请改用self.imageview = nil

      至于为什么它有这么多内存,我不知道,除非它与将图像扩展到其完整大小(按像素)有关,而不是与压缩的 jpg 大小有关,或者与其他数据一起泄露有关UIImageView 对象。

      【讨论】:

      • 我更改了代码并编辑了我上面的代码,虽然问题没有改变。
      • 编辑了我的答案以包含另一个泄漏。
      【解决方案4】:

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

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

      在 addSubview 之后添加这一行:

      [tempImage release];
      

      您不需要 imageView 作为成员,除非您稍后对其进行操作。如果您保留它,请务必在 dealloc 中释放它。一般来说,每个标记为 retain 的属性都应该在 dealloc 中释放,除非你有特定的理由不这样做。

      除非我需要操作它们,例如更改 UILabel 的文本或 UIButton 的状态,否则我通常不会为将存在于视图层次结构中的视图创建属性甚至成员。

      【讨论】:

      • 我在上面编辑了我的代码,还包括了我的 dealloc 方法。然而问题并没有改变。意思是我分配了 20-30 MB,然后每次加载新图表时都会再增加 20-30 MB
      【解决方案5】:

      切换到 ARC 是个好主意。或者,使用静态分析器构建并修复它给您的所有警告。它非常擅长这一点。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-26
        • 1970-01-01
        • 2010-11-23
        • 2011-12-10
        • 2011-05-24
        相关资源
        最近更新 更多