-
內存管理機制的原理是引用計數(shù)
一. Objective-C提供了兩種內存管理方式:
MRC,手動引用計數(shù)器(manual reference counting)
ARC山害,自動引用計數(shù)(automatic reference counting)
引用計數(shù)簡單來說就是統(tǒng)計一塊內存的所有權,當這塊內存被創(chuàng)建出來的時候,它的引用計數(shù)從0增加到1颂砸,表示有一個對象或指針持有這塊內存,擁有這塊內存的所有權死姚,如果這時候有另外一個對象或指針指向這塊內存人乓,那么為了表示這個后來的對象或指針對這塊內存的所有權,引用計數(shù)加1變?yōu)?都毒,之后若有一個對象或指針不再指向這塊內存時色罚,引用計數(shù)減1,表示這個對象或指針不再擁有這塊內存的所有權账劲,當一塊內存的引用計數(shù)變?yōu)?戳护,表示沒有任何對象或指針持有這塊內存金抡,系統(tǒng)便會立刻釋放掉這塊內存。
其中在開發(fā)時引用計數(shù)又分為ARC(自動內存管理)和MRC(手動內存管理)腌且。ARC的本質其實就是MRC梗肝,只不過是系統(tǒng)幫助開發(fā)者管理已創(chuàng)建的對象或內存空間,自動在系統(tǒng)認為合適的時間和地點釋放掉已經(jīng)失去作用的內存空間铺董,原理是一樣的巫击。雖然ARC操作起來很方便,不但減少了代碼量精续,而且降低了內存出錯的概率坝锰,但因為ARC不一定會及時釋放,所以程序有時候可能會占用內存較大重付。而MRC若做得好什黑,通過手動管理,及時釋放掉不需要的內存空間堪夭,便可保證程序長時間運行在良好狀態(tài)上。
二. 在MRC中會引起引用計數(shù)變化的關鍵字有:alloc拣凹,retain森爽,copy,release嚣镜,autorelease爬迟。(strong關鍵字只用于ARC,作用等同于retain)
當對象被創(chuàng)建(alloc菊匿、new或copy等方法)時付呕,其引用計數(shù)初始值為1;
給對象發(fā)送retain消息跌捆,其引用計數(shù)加1徽职;
給對象發(fā)送release消息,其引用計數(shù)減1佩厚;
當對象引用計數(shù)歸0時姆钉,ObjC給對象發(fā)送dealloc消息銷毀對象。
alloc:當一個類的對象創(chuàng)建抄瓦,需要開辟內存空間的時候潮瓶,會使用alloc,alloc是一個類方法钙姊,只能用類調用毯辅,它的作用是開辟一塊新的內存空間,并使這塊內存的引用計數(shù)從0增加到1煞额,注意思恐,是新的內存空間沾谜,每次用類alloc出來的都是一塊新的內存空間,與上一次alloc出來的內存空間沒有必然聯(lián)系壁袄,而且上一次alloc出來的內存空間仍然存在类早,不會被釋放。
retain:retain是一個實例方法嗜逻,只能由對象調用涩僻,它的作用是使這個對象的內存空間的引用計數(shù)加1,并不會新開辟一塊內存空間栈顷,通常于賦值是調用逆日,如:
對象2=[對象1 retain];表示對象2同樣擁有這塊內存的所有權萄凤。若只是簡單地賦值室抽,如:對象2=對象1;那么當對象1的內存空間被釋放的時候靡努,對象2便會成為野指針坪圾,再對對象2進行操作便會造成內存錯誤。copy:copy同樣是一個實例方法惑朦,只能由對象調用兽泄,返回一個新的對象,它的作用是復制一個對象到一塊新的內存空間上漾月,舊內存空間的引用計數(shù)不會變化病梢,新的內存空間的引用計數(shù)從0增加到1,也就是說梁肿,雖然內容一樣蜓陌,但實質上是兩塊內存,相當于克隆吩蔑,一個變成兩個钮热。其中copy又分為淺拷貝、深拷貝和真正的深拷貝烛芬,淺拷貝只是拷貝地址與retain等同霉旗;深拷貝是拷貝內容,會新開辟新內存蛀骇,與retain不一樣厌秒;真正的深拷貝是對于容器類來說的,如數(shù)組類擅憔、字典類和集合類(包括可變和不可變)鸵闪,假設有一個數(shù)組類對象,普通的深拷貝會開辟一塊新內存存放這個對象暑诸,但這個數(shù)組對象里面的各個元素的地址卻沒有改變也就是說數(shù)組元素只是進行了retain或者淺拷貝而已蚌讼,并沒有創(chuàng)建新的內存空間辟灰,而真正的深拷貝,不但數(shù)組對象本身進行了深拷貝篡石,連數(shù)組元素都進行了深拷貝芥喇,即為各個數(shù)組元素開辟了新的內存空間。
release:release是一個實例方法凰萨,同樣只能由對象調用继控,它的作用是使對象的內存空間的引用計數(shù)減1,若引用計數(shù)變?yōu)?則系統(tǒng)會立刻釋放掉這塊內存胖眷。如果引用計數(shù)為0的基礎上再調用release武通,便會造成過度釋放,使內存崩潰珊搀;
autorelease:autorelease是一個實例方法冶忱,同樣只能由對象調用,它的作用于release類似境析,但不是立刻減1囚枪,相當于一個延遲的release,通常用于方法返回值的釋放劳淆,如便利構造器眶拉。autorelease會在程序走出自動釋放池時執(zhí)行,通常系統(tǒng)會自動生成自動釋放池(即使是MRC下)憔儿,也可以自己設定自動釋放池,如:
@autoreleasepool{
obj= [[NSObject alloc]init];
[obj autorelease];
}
當程序走出“}”時obj的引用計數(shù)就會減1.
三. 自動釋放池
-
Autoreleasepool的原理
自動釋放池放可,系統(tǒng)有一個現(xiàn)成的自動內存管理池谒臼,它會隨著每一個mainRunloop的結束而釋放其中的對像;
自動釋放池也可以手動創(chuàng)建耀里,它可以讓pool中的對象在執(zhí)行完代碼后馬上被釋放蜈缤,可以起到優(yōu)化內存,防止內存溢出的效果(如視頻針圖片的切換時冯挎、創(chuàng)建大量臨時對象時等)
autorelease:自動釋放底哥,使對象在超出指定的生存范圍時能夠自動并正確地釋放 (release 即是立即釋放)
如:循環(huán)內產(chǎn)生大量的臨時對象,直至循環(huán)結束才釋放房官,可能導致內存泄漏趾徽。因此,在循環(huán)中創(chuàng)建自己的autoReleasePool翰守,及時釋放占用內存大的臨時變量孵奶,減少內存占用峰值
for (int i = 0; i < 10000; i ++) {
@autoreleasepool {
Person* person = [[Person alloc] init];
[person eat];
}
}
-
從mrc到arc的轉變
項目 -> Build Phases -> Compile Sources 找到要修改的文件
如果是ARC工程添加MRC文件則輸入:-fno-objc-arc
如果是MRC工程添加ARC文件則輸入:-fobjc-arc
四. block內存管理
block本身是像對象一樣可以retain,和release蜡峰。但是了袁,block在創(chuàng)建的時候朗恳,它的內存是分配在棧(stack)上,而不是在堆(heap)上载绿。
1. @property(copy, nonatomic) void(^block)(void);
mrc中 copy會把block從棧上移動到堆上粥诫。
2. @property(strong, nonatomic) void(^block)(void);
arc即時由強引用strong將其從棧復制到堆
block在一開始是處在stack上的,這是為了考慮到效率的原因崭庸,但是怀浆,有時候是需要block的生命周期長于一開始的stack,這時冀自,我們就通過copy block 來將block復制到heap揉稚。
arc中默認的對象聲明都是strong性質的,在兩個或兩個以上的類相互引用時熬粗,會導致循環(huán)引用搀玖,其中一方需要用weak修飾,才不會造成retainCycle驻呐,如:delegate 屬性用weak聲明灌诅;mrc中即用assign修飾 。
在block中引用block所屬的類含末、實例變量或類的屬性也會導致循環(huán)引用
self.block = ^{
[self doSomething];
};
arc中用__weak修飾self猜拾、mrc中用__block修飾,如下代碼:
__weak ViewController* weakSelf = self;//arc
//__block ViewController* weakSelf = self;//mrc
self.block = ^{
[weakSelf doSomething];
};