OS平台記憶體常見問題

來源:互聯網
上載者:User
iOS記憶體暴增問題追查與使用陷阱    (2011-11-29
08:11:57)

iOS平台的記憶體使用量引用計數的機制,並且引入了半自動釋放機制;這種使用上的多樣性,導致開發人員在記憶體使用量上非常容易出現記憶體流失和記憶體莫名的增長情況; 本文會介紹iOS平台的記憶體使用量原則與使用陷阱; 深度剖析autorelease機制;低記憶體警示後的處理流程;並結合自身執行個體介紹記憶體暴增的問題追查記錄以及相關工具的使用方式;

iOS平台記憶體常見問題

作為iOS平台的開發人員,是否曾經為記憶體問題而苦惱過?記憶體莫名的持續增長,程式莫名的crash,難以發現的記憶體流失,這些都是iOS平台記憶體相關的常見問題;本文將會詳細介紹iOS平台的記憶體管理機制,autorelease機制和記憶體的使用陷阱,這些將會解決iOS平台記憶體上的大部分問題,提高了程式的穩定性;
1 iOS平台記憶體管理介紹

iOS平台的記憶體管理採用引用計數的機制;當建立一個對象時使用alloc或者allWithZone方法時,引用計數就會+1;當釋放對象使用release方法時,引用計數就是-1;這就意味著每一個對象都會跟蹤有多少其他對象引用它,一旦引用計數為0,該對象的記憶體就會被釋放掉;另外,iOS也提供了一種延時釋放的機制AutoRelease,以這種方式申請的記憶體,開發人員無需手動釋放,系統會在某一時機釋放該記憶體;
由於iOS平台的這種記憶體管理的多樣性,導致開發人員在記憶體使用量上很容易出現記憶體流失或者程式莫名崩潰的情況,本文會詳細介紹iOS平台記憶體的使用規範與技巧以及如何利用工具避免或者發現問題;

是記憶體從申請到釋放的一個完整樣本:


2 iOS平台記憶體使用量原則
2.1 對象的所有權與銷毀
2.1.1 誰建立,誰釋放;

如果是以alloc,new或者copy,mutableCopy建立的對象,則必須調用release或者autorelease方法釋放記憶體;
如果沒有釋放,則導致記憶體流失!
2.1.2 誰retain,誰釋放;

如果對一個對象發送 retain訊息,其引用計數會+1,則使用完必鬚髮送release或者autorelease方法釋放記憶體或恢複引用計數;
如果沒有釋放,則導致記憶體流失!
2.1.3 沒建立且沒retain,別釋放;

不要釋放那些不是自己alloc或者retain的對象,否則程式會crash;

不要釋放autorelease的對象,否則程式會crash;
2.2 對象的深拷貝與淺拷貝

一般來說,複製一個對象包括建立一個新的執行個體,並以原始對象中的值初始化這個新的執行個體。複製非指標型執行個體變數的值很簡單,比如布爾,整數和浮點數。複製指 針型執行個體變數有兩種方法。一種方法稱為淺拷貝,即將原始對象的指標值複製到副本中。因此,原始對象和副本共用引用資料。另一種方法稱為深拷貝,即複製指標 所引用的資料,並將其賦給副本的執行個體變數。
2.2.1 深拷貝

深拷貝的流程是 先建立一個新的對象且引用計數為1,並用舊對象的值初始化這個新對象;

ClassA* objA = [[ClassA alloc] init];

ClassA* objB = [objA copy];

objB是一個新對象,引用計數為1,且objB的資料等同objA的資料;

注意: objB需要釋放,否則會引起記憶體流失!
2.2.2 淺拷貝

淺拷貝的流程是,無需引入新的對象,把原有對象的引用計數+1即可

ClassA* objA = [[ClassA alloc] init];

ClassA* objB = [objA retain];

注意: objB需要釋放,恢複objA的引用計數,否則會引起記憶體流失!
2.3對象的存取方法
2.3.1 屬性聲明和實現

變數聲明的常用屬性類型包括readonly,assign,retain和copy;且系統會自動為聲明了屬性的變數產生set和get函數;
readonly屬性: 只能讀,不能寫;
assign屬性: 是預設屬性,直接賦值,沒有任何保留與釋放問題;
retain屬性: 會增加原有對象的引用計數並且在賦值前會釋放原有對象,然後在進行賦值;
copy屬性:  會複製原有對象,並在賦值前釋放原有對象,然後在進行賦值;
2.3.2 使用屬性聲明可能帶來的隱患

當一個非指標變數使用retain(或者copy)這個屬性時,盡量不要顯性的release這個變數;直接給這個變數置空即可;否則容易產生過度釋放,導致程式crash; 例如:

ClassA類的strName是NSString* 類型的變數且聲明的屬性為retain;

ClassA.strName = nil;  /* 釋放原有對象且對此對象賦值為空白 */

[ClassA.strName release]; /* strName記憶體可能已經被釋放過了,將導致程式crash */

Assign這個屬性一般是非指標變數(布爾類型,整形等)時用這個類型;屬於直接賦值型,不需要考慮記憶體的保留與釋放;

如果一個指標類型的變數使用assign類型的屬性,有可能引用已經釋放的變數;導致程式crash; 例如:

ClassB* obj =[[[ClassB alloc] init] autorelease];

……

ClassA.strName = obj; /* strName 指向obj的記憶體位址*/

後續在使用ClassA.strName的時候, 因為obj是autorelease的,可能obj的記憶體已經被回收;導致引用無效記憶體,程式crash;
3iOS平台AutoRelease機制
3.1 自動釋放池的常見問題

大家在開發iOS程式的時候,是否遇到過在列表滑動的情況記憶體莫名的增長,頻繁訪問圖片的時候記憶體莫名的增長,頻繁的開啟和關閉資料庫的時候記憶體莫名的增長…… 這些都是拜iOS的autorelease機制所賜;具體分析如下:

1: 滑動列表的時候,記憶體出現莫名的增長,原因可能有如下可能:

1:沒有使用UITableView的reuse機制; 導致每顯示一個cell都用autorelease的方式重新alloc一次; 導致cell的記憶體不斷的增加;

2:每個cell會顯示一個單獨的UIView, 在UIView發生記憶體流失,導致cell的記憶體不斷增長;

2: 頻繁訪問圖片的時候,記憶體莫名的增長;

頻繁的訪問網狀圖片,導致iOS內部API,會不斷的分配autorelease方式的buffer來處理圖片的解碼與顯示; 利用圖片cache可以緩解一下此問題;


3: 頻繁開啟和關閉SQLite,導致記憶體不斷的增長;

在進行SQLite頻繁開啟和關閉操作,而且讀寫的資料buffer較大,那麼SQLite在每次開啟與關閉的時候,都會利用autorelease的方式分配51K的記憶體; 如果訪問次數很多,記憶體馬上就會頂到幾十兆,甚至上百兆! 所以針對頻繁的讀寫資料庫且資料buffer較大的情況, 可以設定SQLite的長串連方式;避免頻繁的開啟和關閉資料庫;
3.2 自動釋放池的概念

NSAutoreleasePool內部包含一個數組(NSMutableArray),用來儲存聲名為autorelease的所有對象。如果一個對象聲明為autorelease,系統所做的工作就是把這個對象加入到這個數組中去。

ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1,把此對象加入autorelease pool中

NSAutoreleasePool自身在銷毀的時候,會遍曆一遍這個數組,release數組中的每個成員。如果此時數組中成員的retain count為1,那麼release之後,retain count為0,對象正式被銷毀。如果此時數組中成員的retain count大於1,那麼release之後,retain count大於0,此對象依然沒有被銷毀,記憶體泄露。
3.3 自動釋放池的範圍與嵌套
AutoreleasePool是可以嵌套使用的!

池是被嵌套的,嵌套的結果是個棧,同一線程只有當前棧頂pool執行個體是可用的:


當短生命週期內,比如一個迴圈中,會產生大量的臨時記憶體,可以建立一個臨時的autorelease pool,這樣可以達到快速回收記憶體的目的;
3.4 自動施放池的手動建立與自動建立
3.4.1 需要手動建立自動釋放池
●如果你正在編寫一個不是基於Application Kit的程式,比如命令列工具,則沒有對自動釋放池的內建支援;你必須自己建立它們。
●如果你產生了一個從屬線程,則一旦該線程開始執行,你必須立即建立你自己的自動釋放池;否則,你將會泄漏對象。
●如果你編寫了一個迴圈,其中建立了許多臨時對象,你可以在迴圈內部建立一個自動釋放池,以便在下次迭代之前銷毀這些對象。這可以協助減少應用程式的最大記憶體佔用量。
3.4.2 系統自動建立自動釋放池

Application Kit會在一個事件周期(或事件迴圈迭代)的開端—比如滑鼠按下事件—自動建立一個自動釋放池,並且在事件周期的結尾釋放它.
4 iOS平台記憶體使用量陷阱
4.1 重複釋放

在前文已經提到,不要釋放不是自己建立的對象;
釋放自己的autorelease對象,app會crash;
釋放系統的autorelease對象,app會crash;
4.2 循環參考


循環參考,容易產生野引用,記憶體無法回收,最終導致記憶體流失!可以通過弱引用的方式來打破循環參考鏈;所謂的弱引用就是不需要retain,直接賦值的方式,這樣的話,可以避免循環參考的問題,但是需要注意的是,避免重複釋放的問題;
5 iOS平台記憶體警示機制

由於iOS平台的記憶體管理機制,不支援虛擬記憶體,所以在記憶體不足的情況,不會去Ram上建立虛擬記憶體;所以一旦出現記憶體不足的情況,iOS平台會通知所有已經啟動並執行app,不論是前台app還是後台掛起的app,都會收到 memory warning的notice;一旦app收到memory warning的notice,就應該回收佔用記憶體較大的變數;
5.1 記憶體警示處理流程

1: app收到系統發過來的memory warning的notice;

2: app釋放佔用較大的記憶體;

3: 系統回收此app所建立的autorelease的對象;

4: app返回到已經開啟的頁面時,系統重新調用viewdidload方法,view重新載入頁面資料;重新顯示;
5.2 記憶體警示測試方法

在Simulate上可以類比低記憶體警示訊息;

iOS模擬器 -> 硬體 -> 類比記憶體警告;

開發人員可以在模擬器上來類比手機上的低記憶體警示情況,可以避免由於低記憶體警示引出的app的莫名crash問題;
6 iOS平台記憶體檢查工具
6.1 編譯和分析工具Analyze

iOS的分析工具可以發現編譯中的warning,記憶體流失隱患,甚至還可以檢查出logic上的問題;所以在自測階段一定要解決Analyze發現的問題,可以避免出現嚴重的bug;
記憶體流失隱患提示:

Potential Leak of an object allocated on line ……
資料賦值隱患提示:

The left operand of …… is a garbage value;
對象引用隱患提示:

Reference-Counted object is used after it is released;


以上提示均比較嚴重,可能會引起嚴重問題,需要開發人員密切關注!
6.2 記憶體偵查工具
6.2.1 記憶體流失偵查工具—Leak

Leak工具可以很容易的統計所有記憶體流失的點,而且還可以顯示在那個檔案,哪行代碼有記憶體流失,這樣定位問題比較容易,也比較方面;但是Leak在統計記憶體流失的時候會把autorelease方式的記憶體也統計進來; 所以我們在尋找記憶體流失情況的時候,可以autorelease的情況忽略掉;

Leak工具:



通過Leak工具可以很快發現代碼中的記憶體流失,通過工具也可以很快找到發生記憶體流失的程式碼片段:

6.2.2 記憶體猛增偵查工具—Allocati*****

Allocati*****工具可以很容易的列出所有分配記憶體的點,這樣我們可以按照分配記憶體大小來進行排序, 這樣可以很容易的發現哪些點分配的記憶體最多,而且是持續分配,這樣我們來針對性的分析這些持續分配較大記憶體的地方;


此工具會顯示出所有申請記憶體的地方,並統計申請的次數和大小; 從這個列表中可以找出記憶體申請次數最多且申請記憶體最大的語句;從而分析出哪些地方使用的記憶體最多,進而可以最佳化和改進;


是按照申請記憶體多少來排序的,可以方便的瞭解哪些代碼申請的記憶體多;
7 參考資料
http://www.cocoachina.com/bbs/read.php?tid=15963
http://developer.apple.com/library/IOs/navigation/轉自:http://www.cocoachina.com/bbs/read.php?tid=94017

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.