iOS內存問題

1. 用ARC管理內存

ARC(Automatic ReferenceCounting, 自動引用計數)和iOS5一起發(fā)布蔬浙,它避免了最常見的也就是經常是由于我們忘記釋放內存所造成的內存泄露儿奶。它自動為你管理retain和release的過程锨亏,所以你就不必去手動干預了.除了幫你避免內存泄露将宪,ARC還可以幫你提高性能胧谈,它能保證釋放掉不再需要的對象的內存。

2.避免過于龐大的XIB

iOS5中加入的Storyboards(分鏡)正在快速取代XIB室梅。然而XIB在一些場景中仍然很有用戏仓。比如你的app需要適應iOS5之前的設備,或者你有一個自定義的可重用的view,你就不可避免地要用到他們亡鼠。

如果你不得不XIB的話赏殃,使他們盡量簡單。嘗試為每個Controller配置一個單獨的XIB间涵,盡可能把一個View Controller的view層次結構分散到單獨的XIB中去仁热。

注意:當你加載一個XIB的時候所有內容都被放在了內存里,包括任何圖片勾哩。如果有一個不會即刻用到的view股耽,你這就是在浪費寶貴的內存資源了根盒。Storyboards就是另一碼事兒了,storyboard僅在需要時實例化一個view controller.

3.常見的加載圖片的方式有兩種物蝙,一個是用`imageNamed`,二是用`imageWithContentsOfFile`敢艰,第一種比較常見一點诬乞。

差別:`imageNamed`的優(yōu)點是當加載時會緩存圖片。`imageNamed`的文檔中這么說:這個方法用一個指定的名字在系統(tǒng)緩存中查找并返回一個圖片對象如果它存在的話钠导。如果緩存中沒有找到相應的圖片震嫉,這個方法從指定的文檔中加載然后緩存并返回這個對象。

相反的牡属,`imageWithContentsOfFile`僅加載圖片票堵。

下面的代碼說明了這兩種方法的用法:

UIImage *img = [UIImage imageNamed:@"myImage"];// caching

// or

UIImage *img = [UIImage imageWithContentsOfFile:@"myImage"];// no caching

如果你要加載一個大圖片而且是一次性使用,那么就沒必要緩存這個圖片逮栅,用`imageWithContentsOfFile`足矣悴势,這樣不會浪費內存來緩存它。

然而措伐,在圖片反復重用的情況下`imageNamed`是一個好得多的選擇特纤。

4.選擇正確的數據存儲選項

當存儲大塊數據時"

· 使用`NSUerDefaults`:雖然它很nice也很便捷,但是它只適用于小數據侥加,比如一些簡單的布爾型的設置選項捧存,再大點你就要考慮其它方式了

· 使用XML, JSON, 或者 plist :你需要讀取整個文件到內存里去解析,這樣是很不經濟的担败。使用SAX又是一個很麻煩的事情昔穴。

· 使用NSCoding存檔 :不幸的是,它也需要讀寫文件提前,所以也有以上問題吗货。

在這種應用場景下,使用SQLite 或者 Core Data比較好岖研。使用這些技術你用特定的查詢語句就能只加載你需要的對象卿操。

· 使用類似SQLite的本地SQL數據庫?

· 使用 Core Data

在性能層面來講枚驻,SQLite和Core Data是很相似的惯豆。他們的不同在于具體使用方法。Core Data代表一個對象的graph model卑雁,但SQLite就是一個DBMS拓售。Apple在一般情況下建議使用Core Data窥摄,但是如果你有理由不使用它,那么就去使用更加底層的SQLite吧础淤。

如果你使用SQLite崭放,你可以用FMDB(https://GitHub.com/ccgus/fmdb)這個庫來簡化SQLite的操作哨苛,這樣你就不用花很多經歷了解SQLite的 API了。

5. 減少使用Web特性

UIWebView很有用币砂,用它來展示網頁內容或者創(chuàng)建UIKit很難做到的動畫效果是很簡單的一件事建峭。

但是你可能有注意到UIWebView并不像驅動Safari的那么快。這是由于以JIT compilation為特色的Webkit的Nitro Engine的限制决摧。

盡可能移除不必要的javascript亿蒸,避免使用過大的框架。能只用原生js就更好了掌桩。

另外边锁,盡可能異步加載例如用戶行為統(tǒng)計script這種不影響頁面表達的javascript。

javascript:通過JS波岛,把一個頁面全我們想要的意思進行渲染茅坛,執(zhí)行相應的功能,生成相應的效果则拷,比如贡蓖,顯示當前系統(tǒng)時間,比如隔躲,顯示實時信息的更新.最后摩梧,永遠要注意你使用的圖片,保證圖片的符合你使用的大小宣旱。使用Sprite sheet提高加載速度和節(jié)約內存仅父。

6.避免反復處理數據

許多應用需要從服務器加載功能所需的常為JSON或者XML格式的數據。在服務器端和客戶端使用相同的數據結構很重要浑吟。在內存中操作數據使它們滿足你的數據結構是開銷很大的笙纤。

比如你需要數據來展示一個table view,最好直接從服務器取array結構的數據以避免額外的中間數據結構改變。

類似的组力,如果需要從特定key中取數據省容,那么就使用鍵值對的dictionary。

7.IBOutlet 對象需要release

8.特別是UIScrollView上add相同SubView燎字。一定要記得清除之前的SubView腥椒,并且在dealloc函數中執(zhí)行該方法

for (UIView* sbViewin scrvBg.subviews)

{

[sbView removeFromSuperview];

}

這里還有個獲得subView的小技巧:

[subView setTag:300];

subView = [self.viewviewWithTag:300]

9.dealloc不一定會被調用,所以可以自己手寫一個myRelease方法候衍,當退出該界面的時候手動調用release需要釋放的對象笼蛛,并且將其置為nil。

10.記住:如果你不太明白UIView的drawRect的調用時機蛉鹿,千萬不要輕易往drawRect里寫代碼滨砍,特別是沒有立即release的對象。很容易在這里因為多次調用了drawRect而沒有release該對象導致內存溢出。

iOS的繪圖操作是在UIView類的drawRect方法中完成的

iOS平臺的內存管理采用引用計數的機制惋戏;

當創(chuàng)建一個對象時使用alloc或者allWithZone方法時领追,引用計數就會+1;當釋放對象使用release方法時响逢,引用計數就是-1绒窑; 這就意味著每一個對象都會跟蹤有多少其他對象引用它,一旦引用計數為0舔亭,該對象的內存就會被釋放掉回论;另外,iOS也提供了一種延時釋放的機制 AutoRelease分歇,以這種方式申請的內存,開發(fā)者無需手動釋放欧漱,系統(tǒng)會在某一時機釋放該內存职抡; 開發(fā)者在內存使用上很容易出現內存泄漏或者程序莫名崩潰的情況

2 iOS平臺內存使用原則

如果是以alloc,new或者copy误甚,mutableCopy創(chuàng)建的對象缚甩,則必須調用release或者autorelease方法釋放內存;如果沒有釋放窑邦,則導致內存泄漏擅威!

2.1.2 誰retain,誰釋放冈钦;

如果對一個對象發(fā)送 retain消息郊丛,其引用計數會+1,則使用完必須發(fā)送release或者autorelease方法釋放內存或恢復引用計數瞧筛;如果沒有釋放厉熟,則導致內存泄漏!

2.1.3 沒創(chuàng)建且沒retain较幌,別釋放揍瑟;

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

不要釋放autorelease的對象绢片,否則程序會crash;

2.2 對象的深拷貝與淺拷貝

一般來說岛琼,復制一個對象包括創(chuàng)建一個新的實例底循,并以原始對象中的值初始化這個新的實例。 復制非指針型實例變量的值很簡單衷恭,比如布爾此叠,整數和浮點數。復制指 針型實例變量有兩種方法。一種方法稱為淺拷貝灭袁,即將原始對象的指針值復制到副本中猬错。因此,原始對象和副本共享引用數據茸歧。另一種方法稱為深拷貝倦炒,即復制指針 所引用的數據,并將其賦給副本的實例變量软瞎。

2.2.1 深拷貝

深拷貝的流程是 先創(chuàng)建一個新的對象且引用計數為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施逾;且系統(tǒng)會自動為聲明了屬性的變量生成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的內存地址*/

后續(xù)在使用ClassA.strName的時候悲立, 因為obj是autorelease的,可能obj的內存已經被回收新博;導致引用無效內存薪夕,程序crash;

3iOS平臺AutoRelease機制

3.1 自動釋放池的常見問題

大家在開發(fā)iOS程序的時候赫悄,是否遇到過在列表滑動的情況內存莫名的增長寥殖,頻繁訪問圖片的時候內存莫名的增長,頻繁的打開和關閉數據庫的時候內存莫名的增長…… 這些都是拜iOS的autorelease機制所賜涩蜘;具體分析如下:

1: 滑動列表的時候,內存出現莫名的增長熏纯,原因可能有如下可能:

1:沒有使用UITableView的reuse機制同诫; 導致每顯示一個cell都用autorelease的方式重新alloc一次; 導致cell的內存不斷的增加樟澜;

2:每個cell會顯示一個單獨的UIView误窖, 在UIView發(fā)生內存泄漏,導致cell的內存不斷增長秩贰;

2: 頻繁訪問圖片的時候霹俺,內存莫名的增長;

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

3: 頻繁打開和關閉SQLite想际,導致內存不斷的增長;

在進行SQLite頻繁打開和關閉操作溪厘,而且讀寫的數據buffer較大胡本,那么 SQLite在每次打開與關閉的時候,都會利用autorelease的方式分配51K的內存畸悬; 如果訪問次數很多侧甫,內存馬上就會頂到幾十兆,甚至上百兆! 所以針對頻繁的讀寫數據庫且數據buffer較大的情況披粟, 可以設置SQLite的長連接方式咒锻;避免頻繁的打開和關閉數據庫;

3.2 自動釋放池的概念

NSAutoreleasePool內部包含一個數組(NSMutableArray)僻爽,用來保存聲名為autorelease的所有對象虫碉。如果一個對象聲明為autorelease,系統(tǒng)所做的工作就是把這個對象加入到這個數組中去胸梆。

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實例是可用的:

當短生命周期內,比如一個循環(huán)中唉擂,會產生大量的臨時內存餐屎,可以創(chuàng)建一個臨時的autorelease pool,這樣可以達到快速回收內存的目的玩祟;

3.4 自動施放池的手動創(chuàng)建與自動創(chuàng)建

3.4.1 需要手動創(chuàng)建自動釋放池

●如果你正在編寫一個不是基于Application Kit的程序腹缩,比如命令行工具,則沒有對自動釋放池的內置支持空扎;你必須自己創(chuàng)建它們庆聘。

●如果你生成了一個從屬線程,則一旦該線程開始執(zhí)行勺卢,你必須立即創(chuàng)建你自己的自動釋放池伙判;否則,你將會泄漏對象黑忱。

●如果你編寫了一個循環(huán)宴抚,其中創(chuàng)建了許多臨時對象勒魔,你可以在循環(huán)內部創(chuàng)建一個自動釋放池,以便在下次迭代之前銷毀這些對象菇曲。這可以幫助減少應用程序的最大內存占用量冠绢。

3.4.2 系統(tǒng)自動創(chuàng)建自動釋放池

Application Kit會在一個事件周期(或事件循環(huán)迭代)的開端—比如鼠標按下事件—自動創(chuàng)建一個自動釋放池,并且在事件周期的結尾釋放它.

4 iOS平臺內存使用陷阱

4.1 重復釋放

在前文已經提到常潮,不要釋放不是自己創(chuàng)建的對象弟胀;

釋放自己的autorelease對象,app會crash喊式;

釋放系統(tǒng)的autorelease對象孵户,app會crash;

4.2 循環(huán)引用

循環(huán)引用岔留,容易產生野引用夏哭,內存無法回收,最終導致內存泄漏献联!可以通過弱引用的方式來打破循環(huán)引用鏈竖配;所謂的弱引用就是不需要retain,直接賦值的方式里逆,這樣的話进胯,可以避免循環(huán)引用的問題,但是需要注意的是原押,避免重復釋放的問題龄减;

5 iOS平臺內存報警機制

由于iOS平臺的內存管理機制,不支持虛擬內存班眯,所以在內存不足的情況,不會去Ram上 創(chuàng)建虛擬內存烁巫;所以一旦出現內存不足的情況署隘,iOS平臺會通知所有已經運行的app,不論是前臺app還是后臺掛起的app亚隙,都會收到 memory warning的notice磁餐;一旦app收到memory warning的notice,就應該回收占用內存較大的變量阿弃;

5內存報警處理流程

1: app收到系統(tǒng)發(fā)過來的memory warning的notice诊霹;

2: app釋放占用較大的內存;

3: 系統(tǒng)回收此app所創(chuàng)建的autorelease的對象渣淳;

4: app返回到已經打開的頁面時脾还,系統(tǒng)重新調用viewdidload方法,view重新加載頁面數據入愧;重新顯示鄙漏;

5.2 內存報警測試方法

做iOS開發(fā)在模擬器上可以通過 Hardware -> Simulate Memory Warning 模擬內存警告

開發(fā)者可以在模擬器上來模擬手機上的低內存報警情況嗤谚,可以避免由于低內存報警引出的app的莫名crash問題;

6 iOS平臺內存檢查工具

6.1 編譯和分析工具Analyze

iOS的分析工具可以發(fā)現編譯中的warning怔蚌,內存泄漏隱患巩步,甚至還可以檢查出logic上的問題;所以在自測階段一定要解決Analyze發(fā)現的問題桦踊,可以避免出現嚴重的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;

以上提示均比較嚴重,可能會引起嚴重問題籍胯,需要開發(fā)者密切關注竟闪!

6.2 內存檢測工具

內存泄漏檢測工具—Leak

Leak工具可以很容易的統(tǒng)計所有內存泄漏的點,而且還可以顯示在那個文件芒炼,哪行代碼有 內存泄漏瘫怜,這樣定位問題比較容易,也比較方面本刽;但是Leak在統(tǒng)計內存泄漏的時候會把autorelease方式的內存也統(tǒng)計進來鲸湃; 所以我們在查找內存泄漏情況的時候,可以autorelease的情況忽略掉子寓;

Leak工具:通過Leak工具可以很快發(fā)現代碼中的內存泄漏暗挑,通過工具也可以很快找到發(fā)生內存泄漏的代碼段:

6.2內存猛增檢測工具—Allocations

Allocations工具可以很容易的列出所有分配內存的點,這樣我們可以按照分配內存大小來進行排序斜友, 這樣可以很容易的發(fā)現哪些點分配的內存最多炸裆,而且是持續(xù)分配,這樣我們來針對性的分析這些持續(xù)分配較大內存的地方鲜屏;

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末烹看,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子洛史,更是在濱河造成了極大的恐慌惯殊,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件也殖,死亡現場離奇詭異土思,居然都是意外死亡,警方通過查閱死者的電腦和手機忆嗜,發(fā)現死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門己儒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人捆毫,你說我怎么就攤上這事闪湾。” “怎么了绩卤?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵响谓,是天一觀的道長损合。 經常有香客問我,道長娘纷,這世上最難降的妖魔是什么嫁审? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮赖晶,結果婚禮上律适,老公的妹妹穿的比我還像新娘。我一直安慰自己遏插,他們只是感情好捂贿,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著胳嘲,像睡著了一般厂僧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上了牛,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天颜屠,我揣著相機與錄音,去河邊找鬼鹰祸。 笑死甫窟,一個胖子當著我的面吹牛,可吹牛的內容都是我干的蛙婴。 我是一名探鬼主播粗井,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼街图!你這毒婦竟也來了浇衬?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤餐济,失蹤者是張志新(化名)和其女友劉穎耘擂,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體颤介,經...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年赞赖,在試婚紗的時候發(fā)現自己被綠了滚朵。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡前域,死狀恐怖辕近,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情匿垄,我是刑警寧澤移宅,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布归粉,位于F島的核電站,受9級特大地震影響漏峰,放射性物質發(fā)生泄漏糠悼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一浅乔、第九天 我趴在偏房一處隱蔽的房頂上張望倔喂。 院中可真熱鬧,春花似錦靖苇、人聲如沸席噩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽悼枢。三九已至,卻和暖如春脾拆,著一層夾襖步出監(jiān)牢的瞬間馒索,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工假丧, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留双揪,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓包帚,卻偏偏與公主長得像渔期,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子渴邦,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內容

  • 1. 內總管理原則(引用計數) IOS的對象都繼承于NSObject, 該對象有一個方法:retainCount...
    lilinjianshu閱讀 2,147評論 0 2
  • iOS平臺的內存使用引用計數的機制疯趟,并且引入了半自動釋放機制;這種使用上的多樣性谋梭,導致開發(fā)者在內存使用上非常容易出...
    XLsn0w閱讀 6,750評論 2 13
  • 內存管理 簡述OC中內存管理機制信峻。與retain配對使用的方法是dealloc還是release,為什么瓮床?需要與a...
    丶逐漸閱讀 1,948評論 1 16
  • 相對電腦而言盹舞,移動設備具有內存少、CPU速度慢等特點隘庄,因此iOS開發(fā)人員需要盡可能優(yōu)化應用的性能踢步。性能優(yōu)化需要考慮...
    攻克乃還_閱讀 351評論 0 0
  • 愛是一個溫暖的詞,它帶給我們柔軟的呵護丑掺、貼心的交流获印,但有些時候,愛會被當做面具戴在另一個詞上面街州,那就是控制兼丰。 大家...
    藍貝殼心理閱讀 412評論 0 0