內(nèi)存管理的方式
為什么要管理內(nèi)存
iOS應用程序出現(xiàn)Crash(閃退),90%的原因是因為內(nèi)存問 題。
在一個擁有數(shù)十個甚至是上百個類的的工程里 ,查找內(nèi)存問題極其困難,
學會內(nèi)存管理,能幫我們減少出錯的機率。
內(nèi)存問題體現(xiàn)在兩個-----內(nèi)存溢出、野指針異常霉赡。
內(nèi)部溢出
iOS給每個應用程序分配了一定的內(nèi)存,
用于程序的運行。一旦超出內(nèi)存上限,程序就會Crash。
- 野指針異常
對象的內(nèi)存已經(jīng)被系統(tǒng)回收,但是仍然使用指針操作這塊內(nèi)存方咆。
野指針異常是程序Crash的重要原因之一。
代碼量越大程序越容易出現(xiàn)野指針問題蟀架。
內(nèi)存管理方式
垃圾回收機制(Garbage Collection)瓣赂。
垃圾回收機制:程序員只需要開辟內(nèi)存空間,不需要用代碼的形式釋放,系統(tǒng)來判斷哪些空間不再被使用,并回收這些內(nèi)存空間,以便再次分配。整個回收的過程不需要寫任何代碼,由系統(tǒng)自動完成垃圾回收片拍。Java開發(fā)中一直使用的就是垃圾回收技術(shù)煌集。
- MRC(Manual Reference Counting)。
-人工引用計數(shù):內(nèi)存的開辟和釋放 都由程序代碼進 控制捌省。相對垃圾回收來說,對內(nèi)存的控制更 加靈活,可以在需要釋放的時候及時釋放,對程序員的要求較高,程序員要熟悉內(nèi)存管理的機制苫纤。
ARC(Auto Reference Counting)。
自動引用計數(shù):iOS 5.0的編譯器特性,它允許用戶只開辟空間,不 去釋放空間纲缓。它不是垃圾回收!它的本質(zhì)還是MRC,只是編譯器幫程序員默認加了釋放的代碼卷拘。
ARC是基于MRC的
引用計數(shù)
- C語言中,使用malloc和free,進行堆內(nèi)存的創(chuàng)建和釋放.堆內(nèi)存只有正在使用和銷毀兩種狀態(tài).
- 實際開發(fā)中,可能會遇到兩個以上的指針使用同一塊內(nèi)存。C語言無法記錄內(nèi)存使用者的個數(shù).
OC對象的操作 | OC中對應的方法 |
---|---|
生成對象 | + alloc |
持有對象 | - retain |
釋放對象 | -release/-autorelease |
銷毀對象 | - dealloc |
-
影響引用計數(shù)的方法
- +alloc: 開辟內(nèi)存空間,讓被開辟的內(nèi)存空間的引用計數(shù) 從0變?yōu)?祝高。
- -retain: 引用計數(shù)加1,如果對象之前引用計數(shù)為1,retain之后變?yōu)?
- -copy: 把某一對象的內(nèi)容拷貝一份,拷貝出新的對象, 原有對象的引用計數(shù)不變,新的對象的引用計數(shù)變1栗弟。
- -release: 引用計數(shù)立即減1,如果對象之前的引 計數(shù)為 ,release之后變?yōu)?,如果之前引用計數(shù)為1,release之后變?yōu)?,內(nèi)存被系統(tǒng)回收。
- -autorelease: 未來的某一時刻引 計數(shù)減1 如果對象之前引用計數(shù)為4,autorelease之后仍然為4,未來某一刻會變?yōu)?工闺。
autoreleasepool的使用
- 通過autoreleasepool自動釋放池,控制autoreleasepool對象的釋放乍赫。
- 向一個對象發(fā)送autorelease消息,該對象就會被添加到離autorelease最近的自動釋放池中,當自動釋放池銷毀時,為池中的每一個對象發(fā)送release消息。
NSAutoreleasePool
iOS5之前,使用NSAutoreleasePool自動釋放池類創(chuàng)建對象陆蟆。
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // 動釋放池創(chuàng)建
[pool release]; // 動釋放池銷毀
dealloc
- -dealloc是繼承父類的方法,當對象引用計數(shù)為0的時候,由對象自動調(diào)用 ,銷毀該對象的空間雷厂。
- 重寫dealloc方法,驗證對象的空間是否被回收。
- (void)dealloc {
//這里面寫一些本類使用的其他資源的銷毀操作,并且需要在父類dealloc方法調(diào)用之前
NSLog(@"調(diào)用了銷毀");
//MRC下重寫dealloc方法需要調(diào)用父類的實現(xiàn),ARC下重寫dealloc方法不需要寫[super dealloc],系統(tǒng)會自動調(diào)用
[super dealloc];
}
- 下面代碼會出現(xiàn)什么樣的問題
@autoreleasepool {
for (NSInteger i = 0; i < 1000000000000; i++) {
Person *p = [[Person alloc]init];
[p autorelease];
}
}
//因為autorelease 出自動釋放池才釋放 所以造成內(nèi)存增加
- 解決方法
@autoreleasepool {
for (NSInteger i = 0; i < 1000000000000; i++) {
@autoreleasepool {
Person *p = [[Person alloc]init];
[p autorelease];
}
}
}
//把一個對象添加到一個集合中會對該對象的引用計數(shù)加1,如果移除會將該對象的引用計數(shù)減1
Person *p4 = [[Person alloc] init];
NSMutableArray *arr = [NSMutableArray array];
[arr addObject:p4];
[p4 release];//release alloc的+1
內(nèi)存管理原則
凡是使用了alloc,retain,copy讓內(nèi)存的引用計數(shù) 增加了,就需要使release或者autorele讓內(nèi)存的引 計數(shù)減少遍搞。在一段代碼內(nèi),增加和減少的次數(shù)要相等罗侯。
如果增加的次數(shù)多于減少的次數(shù),會造成內(nèi)存泄露。
如果增加次數(shù)少于減少的次數(shù),會造成過度釋放溪猿。
如果增加的次數(shù)等于減少的次數(shù),還繼續(xù)訪問,造成野指針問題钩杰。