效能最佳化–記憶體泄露問題的解決

來源:互聯網
上載者:User

記憶體流失問題的解決

記憶體流失(Memory Leaks)是當一個對象或變數在使用完成後沒有釋放掉,這個對象一直佔有著這塊記憶體,直到應用停止。如果這種對象過多記憶體就會耗盡,其它的應用就無法運行。這個問題在C++、C和Objective-C的MRR中是比較普遍的問題。

在Objective-C中釋放對象的記憶體是發送release和autorelease訊息,它們都是可以將引用計數減1,當為引用計數為0時候,release訊息會使對象立刻釋放,autorelease訊息會使對象放入記憶體釋放池中延遲釋放。

上代碼:

- (void)viewDidLoad{[super viewDidLoad];NSBundle *bundle = [NSBundle mainBundle];NSString *plistPath = [bundle pathForResource:@"team"ofType:@"plist"];//擷取屬性列表檔案中的全部資料self.listTeams = [[NSArray alloc] initWithContentsOfFile:plistPath];}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{static NSString *CellIdentifier = @”CellIdentifier”;UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];if (cell == nil) {cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];}NSUInteger row = [indexPath row];NSDictionary *rowDict = [self.listTeams objectAtIndex:row];cell.textLabel.text =  [rowDict objectForKey:@"name"];NSString *imagePath = [rowDict objectForKey:@"image"];imagePath = [imagePath stringByAppendingString:@".png"];cell.imageView.image = [UIImage imageNamed:imagePath];cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;return cell;}- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{NSUInteger row = [indexPath row];NSDictionary *rowDict = [self.listTeams objectAtIndex:row];NSString *rowValue  =  [rowDict objectForKey:@"name"];NSString *message = [[NSString alloc] initWithFormat:@”您選擇了%@隊。”, rowValue];UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@”請選擇球隊”message:messagedelegate:selfcancelButtonTitle:@”Ok”otherButtonTitles:nil];[alert show];[tableView deselectRowAtIndexPath:indexPath animated:YES];}

 

大 家看看上面的3個方法會有什麼問題呢?如果代碼是基於ARC的是沒有問題的,遺憾的是基於MRR,上面的代碼都存在記憶體流失的可能性。理論上講內 存泄漏是對象或變數沒有釋放引起的,但實踐證明並非所有的未釋放對象或變數都會導致記憶體流失,這與硬體環境和作業系統環境有關,因此我們需要偵查工具協助 我們找到這些“泄漏點”。

在Xcode中提供了兩種工具協助尋找泄漏點:Analyze和Profile,Analyze是靜態分析工具 可以通過菜單 Product→Analyze啟動,為靜態分析之後的代碼畫面;Profile是動態分析工具,這個工具叫“Instruments”,它是Xcode 整合在一起,可以在Xcode中通過菜單Product→Profile啟動,Instruments有很多Trace Template(跟蹤模板)可以動態分析和跟蹤記憶體、CPU和檔案系統。

我們可以兩個工具結合使用尋找泄漏點,先使用Analyze靜態分析尋找可疑泄漏點,再用Profile動態分析中的Leaks和Allocations跟蹤模板進行動態跟蹤分析,確認這些點是否泄漏,或者是否有新的泄漏出現等。

其 中的線段表明了程式執行的路徑,在這個路徑中,1:說明在25行Objective-C對象引用計數是1,說明在這裡建立了一個 Objective-C對象;2:說明在27行引用計數為1這個,該對象沒有釋放,懷疑有泄漏。這樣的說明已經很明顯的告訴我們問題所在了, [[NSArray alloc] initWithContentsOfFile:plistPath]建立了一個對象,並賦值給 listTeams屬性所代表的成員變數,然而完成了賦值工作之後,建立的對象並沒有顯示地發送release和autorelease訊息。代碼修改

NSArray *array = [[NSArray alloc] initWithContentsOfFile:plistPath];self.listTeams = array;[array release];

 

 

我們看一下tableView:cellForRowAtIndexPath:方法中的疑似泄漏點行末尾的藍色表徵圖展開分析結果

其 中主要是說明UITableViewCell*類型的cell對象在64行有可能存在泄漏。在表視圖中 tableView:cellForRowAtIndexPath:方法是為表視圖儲存格執行個體化並設定資料的,因此cell對象執行個體化後不能馬上 release,應該使用autorelease延遲釋放。可以在建立cell對象的時候發送autorelease訊息,代碼修改如下:

if (cell == nil) {cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];}

 

 

我們看一下tableView:didSelectRowAtIndexPath:方法中的疑似泄漏點有兩個,行末尾的表徵圖展開分析結果。

 

 message對象建立之後沒有釋放,我們只需要在[alert show]之後添加[message release]語句代碼就可以了。在Objective-C中執行個體化對象有兩種方式:

NSString *message = [[NSString alloc] initWithFormat:@”您選擇了%@隊。”, rowValue];                             ①

NSString *message = [NSString stringWithFormat:@"您選擇了%@隊。", rowValue];                           ②

① 行所示以init-開頭構造方法,它的是在alloc之後調用該方法我們稱為“執行個體構造方法”,該方法建立對象所有權是調用者,調用者需要對它的 生命週期負責,具體說負責建立和釋放。而另一種是②行所示string-(去掉NS後類名)開頭方法,它是通過類直接調用我們稱為“類級構造方法”,該方 法是建立的對象所有權非調用者所有,調用者不無權釋放它,否則就會因過渡釋放而“殭屍化”

UIAlertView*類型alert對象建立之後沒有釋放,我們只需要在[alert show]之後添加[alert release]語句代碼就可以了,修改之後的代碼

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{NSUInteger row = [indexPath row];NSDictionary *rowDict = [self.listTeams objectAtIndex:row];NSString *rowValue  =  [rowDict objectForKey:@"name"];NSString *message = [[NSString alloc] initWithFormat:@”您選擇了%@隊。”, rowValue];UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@”請選擇球隊”message:messagedelegate:selfcancelButtonTitle:@”Ok”otherButtonTitles:nil];[alert show];[alert release];[message release];[tableView deselectRowAtIndexPath:indexPath animated:YES];}

 

 

上 面介紹的使用Analyze靜態分析尋找可疑泄漏點,之所以稱為“可疑泄漏點”,但是這些點未必一定泄漏,確認這些點是否泄漏還要通過 Profile動態分析工具Instruments中的Leaks和Allocations跟蹤模板,Analyze靜態分析只是一個理論上的預測過程。 通過菜單Product→Profile啟動, Profile動態分析工具中選擇Leaks模板

Instruments 中雖然是選擇了Leaks模板,但預設情況也會添加Allocations模板,基本上凡是分析記憶體都會使用 Allocations模板,它可以監控記憶體分布情況,選中Allocations模板(圖中①地區),右邊③地區會顯示隨著時間的變化記憶體使用量折線圖 表,同時在④地區會顯示記憶體使用量的詳細資料,其中剛剛對象分配情況。點擊Leaks模板(圖中②地區),可以查看記憶體流失情況,如果在③地區有紅線出現, 則有記憶體流失,④地區會顯示泄漏的對象。

出 現的泄漏是在點擊表視圖中儲存格測試tableView:didSelectRowAtIndexPath:方法方法時候發生的,其中 NSCFString類型的對象發生了泄漏,NSCFString類型在NSFoundation中是NSString*類型。點擊泄漏對象前面的三角形 展開對象,可以看到它們的記憶體位址、佔用位元組、所屬架構和回應程式法資訊。

開啟擴充詳細視圖,可以看到右邊的跟蹤堆棧資訊,其中我們自己應用代碼,可以點擊進入我們程式碼,會開啟對應代碼。

代碼77並不是泄漏點,而是其中的NSString*類型對象在之後發生了泄漏,因此可以斷定是message對象之後沒有釋放導致泄漏。我們修改代碼如下:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{NSUInteger row = [indexPath row];NSDictionary *rowDict = [self.listTeams objectAtIndex:row];NSString *rowValue  =  [rowDict objectForKey:@"name"];NSString *message = [[NSString alloc] initWithFormat:@”您選擇了%@隊。”, rowValue];UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@”請選擇球隊”message:messagedelegate:selfcancelButtonTitle:@”Ok”otherButtonTitles:nil];[alert show];    [message release];[tableView deselectRowAtIndexPath:indexPath animated:YES];}

 

 

添 加[message release]語句。很多人還會猜測alert對象(UIAlertView*)會有泄漏,因此重新運行Instruments工具,反覆點擊儲存格測 試,並未發現表示記憶體流失的紅線! Instruments工具認為alert對象不釋放不會引起記憶體流失,如果我們想進一步評估它對於記憶體的應用,這個時候我們可以看看 Allocations模板的折線圖表,每次點擊總佔用記憶體數都有所增加,這說明alert對象沒有釋放雖然不是很嚴重,但是也會增加佔用記憶體,因此 alert對象釋放也是必須的。

這就是我們介紹的記憶體流失問題解決方案,事實上記憶體流失是極其複雜問題,工具使用是一方面,經驗是另一方面。提高經驗,然後藉助於工具才是解決記憶體流失的根本。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.