繁体   English   中英

iPhone内存泄漏和Malloc?

[英]iphone memory leaks and malloc?

好吧,即时通讯终于到了要在实际iPad上测试我的iPad App的地步...

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

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

AL1分配:83.9 MB Malloc 48.55 MB:48.55 MB Malloc 34.63 MB:34.63 MB

我试图理解的是明显地如何解决漏洞,还有为什么2MB的映像导致大小的20倍的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];
}

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

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

这就是为什么每次加载映像时都会看到20-30MB的分配,这与保留问题无关(这意味着每分配30MB都不会释放)。

此代码中有很多泄漏。

对于使用alloc创建的每个对象,您都需要在使用alloc其释放。

以下项目泄漏,需要释放

  1. tempString
  2. tempImage
  3. alert

另外,您不需要NSAutoreleasePool ,可可框架会为您创建一个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 ,它将按self.imageview = tempImage保留图像视图,但是当您执行imageview = nil ,它将在不释放内存的情况下使引用无效。 这是另一个泄漏。 尝试使用self.imageview = nil代替。

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

tempImage仍在泄漏。

替换说的那行

imageView = nil;

[self setImageView: nil];

要么

self.imageView = nil;

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

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

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

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

在addSubview之后添加以下行:

[tempImage release];

除非稍后要使用它,否则不需要imageView作为成员。 如果保留它,请确保在dealloc中释放它。 通常,除非有特殊原因,否则每个标记为“保留”的属性都应在dealloc中释放。

我通常不为视图提供属性,甚至不拥有将存在于视图层次结构中的视图成员,除非需要操纵它们,例如更改UILabel的文本或UIButton的状态。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM