簡體   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