IOS面试_1.浅析内存管理
為了開學的面試,就在博客里總結一下面試會問到的問題,今天就來談談內存管理,看到一篇文章非常不錯,http://vinceyuan.cnblogs.com/,深入淺出,推薦大家去看看!
?
Objective-C使用一種(Retain Count)引用計數的機制來管理內存,在OC中,每個對象都持有自己的retain count,引用計數可以理解為就是一個計數器,當對象alloc創建的時候,會自動設置為1,當給對象發送retain消息的時候,引用計數會加1,當給對象發送release消息的時候,引用計數會減1,當引用計數為0的時候,對象會釋放所占用的內存,這就是內存管理的機制,聽起來比較容易吧,下面就進一步分析這種機制。
首先,我們應該知道為什么要這樣做?我們經常在不同的對象中引用相同的對象,例如:假設我們用不同電腦遠程連接到同一臺服務器進行遠程操作,轉化成OC語言就是不同電腦對象引用相同的服務器對象,這時候有一臺電腦在服務器上敲了shutdown命令,讓服務器掛掉了,這時候我們所有電腦都連接不上去了,其他人就工作不了了,引用計數其實就像一個計數開關,只有當沒有電腦連接的時候,計數為0,才允許執行shutdown命令(非常理想狀態下,現實中可不要這樣做)。
不同于java的GC回收機制,java中當沒有對象引用指向原先分配給某個對象的內存時,該內存便成為垃圾。JVM的一個系統級線程會自動釋放該內存塊,除了釋放沒用的對象,垃圾回收也可以清除內存記錄碎片。由于創建對象和垃圾回收器釋放丟棄對象所占的內存空間,內存會出現碎片。碎片是分配給對象的內存塊之間的空閑內存洞。碎片整理將所占用的堆內存移到堆的一端,JVM將整理出的內存分配給新的對象。OC中這種特有的retain count機制,給我們更多權限,讓開發者去控制對象釋放的時間以及如何去釋放,所以我們得更加小心,過早的釋放內存,可能會引起程序崩潰,長時間不釋放占用的內存,程序在運行一段時間后可能會發生內存泄露。
?
? Objective-C采用了引用計數(retain count)。對象的內部保存一個數字,表示被引用的次數。例如,某個對象被兩個指針所指向(引用)那么它的retain count為2。需要銷毀對象的時候,不直接調用dealloc,而是調用release。release會讓retain count減1,只有retain count等于0,系統才會調用dealloc真正銷毀這個對象。
ClassA *obj1 = [[ClassA alloc] init];//對象生成時,retain count = 1[obj1 release]; //release使retain count減1,retain count = 0,dealloc自動被調用,對象被銷毀下面觀看一個例子
ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1 ClassA *obj2 = obj1; //retain count = 1 [obj1 hello]; //輸出hello [obj1 release]; //retain count = 0,對象被銷毀 [obj2 hello]; [obj2 release];obj2引用了obj1,此時retain count為1,當obj1執行完消息釋放后,retain count=0,此時obj2變成了無效指針,這里再執行[obj2 release]會引起內存的過度釋放
所以一定要謹記,不是alloc創建,而是指針賦值的時候,一定要retain,拿到對象的所有權
ClassA *obj1 = [[ClassA alloc] init]; //retain count = 1 ClassA *obj2 = obj1; //retain count = 1 [obj2 retain]; //retain count = 2 [obj1 hello]; //輸出hello [obj1 release]; //retain count = 2 – 1 = 1 [obj2 hello]; //輸出hello [obj2 release]; //retain count = 0,對象被銷毀這樣寫的確可以解決問題,但是如果對象非常多得時候,這樣的操作會不會太繁瑣了點,有沒有簡單一點的解決辦法?所以oc引入了自動釋放池autorelease pool,這也不同于java的全自動垃圾回收
新生成的對象調用autorelease就可以了
ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1 但無需調用release如果存在指針賦值,與上面的代碼也相似
ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1 ClassA *obj2 = obj1; //retain count = 1 [obj2 retain]; //retain count = 2 [obj1 hello]; //輸出hello //對于obj1,無需調用(實際上不能調用)release [obj2 hello]; //輸出hello [obj2 release]; //retain count = 2-1 = 1這里有個有趣的問題,retain count不是1么,還不能銷毀呀,什么時候才能銷毀呢?
所以我們得了解一下autorelease pool的原理機制。
1)autorelease pool不是天生的,需要手動創立。只不過在新建一個iphone項目時,xcode會自動幫你寫好。autorelease pool的真名是NSAutoreleasePool。
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
?
2)NSAutoreleasePool內部包含一個數組(NSMutableArray),用來保存聲明為autorelease的所有對象。如果一個對象聲明為autorelease,系統所做的工作就是把這個對象加入到這個數組中去。
ClassA *obj1 = [[[ClassA alloc] init] autorelease]; //retain count = 1,把此對象加入autorelease pool中3) ??NSAutoreleasePool自身在銷毀的時候,會遍歷一遍這個數組,release數組中的每個成員。如果此時數組中成員的retain count為1,那么release之后,retain count為0,對象正式被銷毀。如果此時數組中成員的retain count大于1,那么release之后,retain count大于0,此對象依然沒有被銷毀,內存泄露。
?
那是不是有了自動釋放池autorelease pool就萬無一失了,其實不然
默認只有一個自動釋放池
int main (int argc, const char *argv[]) { NSAutoreleasePool *pool; pool = [[NSAutoreleasePool alloc] init];// do something[pool release]; return (0); } // main所有標記為autorelease的對象在這個pool內被銷毀,但是如果這個自動釋放池里面含有大量autorelease的對象,還是容易造成內存不足的情況,比如說:
int main (int argc, const char *argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; int i, j; for (i = 0; i < 100; i++ ) {for (j = 0; j < 100000; j++ )[NSString stringWithFormat:@"1234567890"];//產生的對象是autorelease的。 } [pool release]; return (0); } // main這種情況,大量內存被占用,只有poll銷毀的時候,那些聲明為autorelease對象才被銷毀,這對于ios程序來說并不樂觀,iphone內存本身有限,那有沒有更好的解決辦法,所以我們可以用autorelease嵌套機制來控制。
??Objective-C程序中可以嵌套創建多個autorelease pool。在需要大量創建局部變量的時候,可以創建內嵌的autorelease pool來及時釋放內存。
int main (int argc, const char *argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; int i, j; for (i = 0; i < 100; i++ ) {NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];for (j = 0; j < 100000; j++ )[NSString stringWithFormat:@"1234567890"];//產生的對象是autorelease的。[loopPool release]; } [pool release]; return (0); } // main?
轉載于:https://www.cnblogs.com/yueyingsuixing/p/3457767.html
總結
以上是生活随笔為你收集整理的IOS面试_1.浅析内存管理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IOS设计模式的六大设计原则之开放-关闭
- 下一篇: Xcode5搭建Python开发环境