一.內(nèi)存管理的原因
(1)內(nèi)存溢出 內(nèi)存不夠用
(2)野指針異常 指針操作了不屬于自己的存儲空間农渊,指針操作已經(jīng)銷毀的對象
二.內(nèi)存管理的方式
(1)MRC? 手動管理內(nèi)存
(2)ARC? 自動管理內(nèi)存
三.MRC手動管理內(nèi)存
1.引用計數(shù)器
(1)引用計數(shù)器表示有多少人正在使用這個對象。
(2)當(dāng)沒有任何人使用這個對象時, 系統(tǒng)才會回收這個對象, 也就是說當(dāng)對象的引用計數(shù)器為0時,對象占用的內(nèi)存就會被系統(tǒng)回收。
(3)如果對象的計數(shù)器不為0,那么在整個程序運行過程啥辨,它占用的內(nèi)存就不可能被回收(除非整個程序已經(jīng)退出 )
(4)任何一個對象, 剛生下來的時候, 引用計數(shù)器都為1
(5)當(dāng)使用alloc、new或者copy(MutableCopy)創(chuàng)建一個對象時,對象的引用計數(shù)器默認(rèn)就是1
2.引用計數(shù)器的操作
(1)給對象發(fā)送一條retain消息,可以使引用計數(shù)器值+1(retain方法返回對象本身)
(2)給對象發(fā)送一條release消息, 可以使引用計數(shù)器值-1
(3)給對象發(fā)送retainCount消息, 可以獲得當(dāng)前的引用計數(shù)器值(retainCount有時候會不準(zhǔn)確纬霞,建議采用delloc方法來驗證是否完全內(nèi)存釋放)
注意: release并不代表銷毀\回收對象, 僅僅是計數(shù)器-1
3.dealloc方法
(1)當(dāng)一個對象的引用計數(shù)器值為0時,這個對象即將被銷毀,其占用的內(nèi)存被系統(tǒng)回收驱显。
(2)對象即將被銷毀時系統(tǒng)會自動給對象發(fā)送一條dealloc消息 (因此, 從dealloc方法有沒有被調(diào)用,就可以判斷出對象是否被銷毀)
dealloc方法的重寫:
一般會重寫dealloc方法,在這里釋放相關(guān)資源,dealloc就是對象的遺言
一旦重寫了dealloc方法, 就必須調(diào)用[super dealloc],并且放在最后面調(diào)用
-(void)delloc{
[super delloc];
}
4.使用注意
不能直接調(diào)用dealloc方法
一旦對象被回收了, 它占用的內(nèi)存就不再可用,堅持使用會導(dǎo)致程序崩潰(野指針錯誤).
5.內(nèi)存管理規(guī)則
(1)誰創(chuàng)建誰release :
如果你通過alloc诗芜、new或[mutable]copy來創(chuàng)建一個對象,那么你必須調(diào)用release或autorelease埃疫。
誰retain誰release:
(2)只要你調(diào)用了retain伏恐,就必須調(diào)用一次release
總結(jié):
有加就有減
曾經(jīng)讓對象的計數(shù)器+1,就必須在最后讓對象計數(shù)器-1栓霜,最后重寫delloc方法來檢查內(nèi)存是否完全釋放翠桦。
6.多對象內(nèi)存管理
(1)多對象內(nèi)存管理規(guī)則:
只要還有人在用某個對象,那么這個對象就不會被回收
只要你想用這個對象,就讓對象的計數(shù)器+1
當(dāng)你不再使用這個對象時销凑,就讓對象的計數(shù)器-1
(2)setter方法內(nèi)存管理規(guī)則:
retain需要使用的對象
release之前的對象
只有傳入的對象和之前的不同才需要release和retain
- (void)setRoom:(Room *)room
{
// 避免過度釋放(判斷私有成員和局部成員是否相等)
if (room != _room)
{
// 對當(dāng)前正在使用的車(舊車)做一次release
[_room release]丛晌;
// _room = nil;
// 對新車做一次retain操作
_room = [room retain];
}
}
(3)dealloc方法的內(nèi)存管理規(guī)則
- (void)dealloc
{
// 當(dāng)人不在了,代表不用房間了
// 對房間做一次release操作
[_room release];
// 這樣寫逼格高一點? self.room = nil;
[super dealloc];
}
7.@property參數(shù)
這里寫圖片描述
(1)控制set方法的內(nèi)存管理
retain : release舊值斗幼,retain新值(用于OC對象)
assign : 直接賦值澎蛛,不做任何內(nèi)存管理(默認(rèn),用于非OC對象類型)
copy : release舊值蜕窿,copy新值(一般用于NSString *)
(2)控制需不需要生成set方法
readwrite :同時生成set方法和get方法(默認(rèn))
readonly :只會生成get方法
(3)多線程管理
atomic :性能低(默認(rèn))
nonatomic :性能高(iOS開發(fā)中都用這個屬性)
(4)控制set方法和get方法的名稱
setter : 設(shè)置set方法的名稱谋逻,一定有個冒號:
getter : 設(shè)置get方法的名稱
若有bool類型時最好修改getter方法為:(getter = isXXX)
注意: 不同類型的參數(shù)可以組合在一起使用
(5)循環(huán)引用
當(dāng)使用@property屬性聲明兩個對象時,如果同時使用retain桐经,會到時相互引用毁兆,內(nèi)存不會釋放,解決辦法是次询,一個用retain荧恍,一個用assign。
8.autoreleasepool 自動釋放池
(1)在iOS程序運行過程中屯吊,會創(chuàng)建無數(shù)個池子送巡。這些池子都是以棧結(jié)構(gòu)存在(先進(jìn)后出),當(dāng)一個對象調(diào)用autorelease方法時盒卸,會將這個對象放到棧頂?shù)尼尫懦亍?/p>
(2)autorelease是一種支持引用計數(shù)的內(nèi)存管理方式,只要給對象發(fā)送一條autorelease消息,會將對象放到一個自動釋放池中,當(dāng)自動釋放池被銷毀時骗爆,會對池子里面的所有對象做一次release操作
注意:
這里只是發(fā)送release消息,如果當(dāng)時的引用計數(shù)(reference-counted)依然不為0,則該對象依然不會被釋放。
(3)autorelease使用注意事項
并不是放到自動釋放池代碼中,都會自動加入到自動釋放池
在自動釋放池的外部發(fā)送autorelease 不會被加入到自動釋放池中
autorelease是一個方法,只有在自動釋 放池中調(diào)用才有效蔽介。
如果寫了autorelease就不要寫release
只要在自動釋放池中調(diào)用autorelease, 就會將對象放入自動釋放池
自動釋放池中不適宜放占用內(nèi)存比較大的對象
不要連續(xù)調(diào)用autorelease,同時也不要把大量循環(huán)操作放到同一個 @autoreleasepool 之間
@autoreleasepool {
// 創(chuàng)建對象時用autorelease
Person *p? =[ [Person alloc]init]autorelease];
}
// 類方法
+(instancetype)person{
return [[self alloc]init]autorelease]
}
// 類工廠方法
+(instancetype)personWithAge:(int)age
{
return [[[self alloc] initWithAge:age] autorelease];
}
-(void)dealloc
{
NSLog(@"%s", __func__);
[super dealloc];
}
四摘投、ARC 自動引用計數(shù)管理內(nèi)存
1.ARC機制判斷注意點及優(yōu)點
ARC機制判斷,ARC機制下有幾個明顯的標(biāo)志:
不允許調(diào)用對象的release方法
再重寫父類的dealloc方法時,不能再調(diào)用 [super dealloc];
ARC的注意點:
- ARC是編譯器特性虹蓄,而不是運行時特性
- ARC不是其它語言中的垃圾回收,有著本質(zhì)區(qū)別ARC的
優(yōu)點:
- 完全消除了手動管理內(nèi)存的煩瑣
- 基本上能夠避免內(nèi)存泄露有時還能更加快速犀呼,因為編譯器還可以執(zhí)行某些優(yōu)化
2.強指針,弱指針
強指針
默認(rèn)所有指針變量都是強指針
被__strong修飾的指針
Person *p1 = [[Person alloc] init];
__strong? Person *p2 = [[Person alloc] init];
弱指針
被__weak修飾的指針
__weak? Person *p = [[Person alloc] init];
3.ARC下單對象內(nèi)存管理
(1)局部變量釋放對象隨之被釋放
(2)清空指針對象隨之被釋放
(3)默認(rèn)清空所有指針都是強指針
弱指針需要明確說明 :
注意: 千萬不要使用弱指針保存新創(chuàng)建的對象
4.ARC下循環(huán)引用問題
與MRC一樣薇组,當(dāng)兩個對象相互引用時外臂,會出現(xiàn)內(nèi)存泄露的問題,解決辦法是:一個用strong一個用weak律胀。
5.ARC下@property參數(shù)
strong: 用于OC對象, 相當(dāng)于MRC中的retain
weak: 用于OC對象, 相當(dāng)于MRC中的assign
assign: 用于基本數(shù)據(jù)類型, 跟MRC中的assign一樣(默認(rèn)值)
五.如何將MRC轉(zhuǎn)換為ARC
如何進(jìn)行ARC和MRC的混合使用:
轉(zhuǎn)變?yōu)榉茿RC -fno-objc-arc
轉(zhuǎn)變?yōu)锳RC的, -f-objc-arc (不常用)