結論:誰alloc,copy,retain,誰release
管理范圍:任何繼承NSObject的對象,基本數據類型不用進行管理
本質原因:因為對象和基本數據類型在系統中的存儲空間不一樣,局部變量主要存放在棧中,而對象存儲于堆中,當代碼塊結束時這個代碼塊中涉及的所有局部變量會被回收,指向對象的指針也被回收,此時對象已經沒有指針指向,但依然存在于內存中,造成內存泄露。
出現原因:
1.內存溢出:沒有指向對象的指針,但是對象沒有被回收
2.野指針異常:指向僵尸對象的指針,僵尸對象是內存被回收的對象。
給空指針發送消息不會報錯
在每個oc對象內部,都有專門的4個字節的存儲空間來存儲引用計數
內存管理方式:
1.手工引用計數(manual reference counting)
2.自動引用計數(auto reference counting)
MRC的內存管理機制:引用計數
ARC是基于MRC的,ARC是編譯器特性,而不是運行時特性
內存管理原則
(一)原則
只要還有人在使用某個對象,那么這個對象就不會被回收;
只要你想使用這個對象,那么就應該讓這個對象的引用計數器+1;
當你不想使用這個對象時,應該讓對象的引用計數器-1;
(二)誰創建,誰release
(1)如果你通過alloc,new,copy來創建了一個對象,那么你就必須調用release或者autorelease方法
(2)不是你創建的就不用你去負責
第二條意味著通過便利構造器和訪問器間接得到對象,實際上沒有獲得對象的所有權,不需要負責對象的釋放,只有通過alloc,retain,copy等手段得到的對象,才擁有對象的所有權,所以不要對通過便利構造器和訪問器得到的對象進行release
(三)誰retain,誰release
只要你調用了retain,無論這個對象時如何生成的,你都要調用release
(四)總結
有始有終,有加就應該有減。曾經讓某個對象計數器加1,就應該讓其在最后-1.
屬性賦值的內存管理:
retain:應該先對舊的對象執行release,然后對新的對象retain(適用oc對象類型)
assign:直接賦值
copy:對舊的對象執行release,對新的對象copy
retain下的屬性內部實現
- (void) setName:(NSString *)name {
if(_name != name) {
[_name release];
_name = [name retain];
}
}
- (NSString *) name {
return [[_name retain] autorelease];
}
使用retain讓對象的引用計數加1,如果單純賦值沒有使用retain,對象的引用計數不會變化
assign、retain、copy對應不同的setter實現。為實例變量賦值時,盡量使用setter方法,再次賦值時,會把之前值release。
dealloc在對象引用計數為0時自動調用,不要顯式調用。
dealloc實現內部,先要釋放實例變量,然后執行[super dealloc]。
便利構造器的內存管理是借助autorelease實現的。
集合會管理自己的元素。 KVC是一種間接訪問實例變量的方法。 ARC系統管理內存,不需要開發人員手動管理。
當對象autorelease時,會被添加到autoreleasepool中,當autoreleasepool被銷毀時,對象被銷毀
系統自帶的方法中,如果不包含alloc,new,copy等,則這些方法返回的對象都是autorelease的,如[NSDate date];
開發中經常會寫一些類方法來快速創建一個autorelease對象,創建對象時不要直接使用類名,而是使用self
nonatomic設置屬性setter,getter操作不是原子性的,不是線程安全的,atomic是原子性的
OC中copy的作用是:利用一個源對象產生一個副本對象(copy必須遵循NSCopying協議)
特點:1、修改源對象的屬性和行為,不會影響副本對象。
2、修改副本對象的屬性和行為,不會影響源對象。
使用方式:
一個對象可以調用copy或mutableCopy方法來創建一個副本對象。
1、copy:創建的時不可變副本(如NSString、NSArray、NSDictionary)。
2、mutableCopy:創建的可變副本(如NSMutableString、NSMutableArray、NSMutableDictionary)。
使用copy功能的前提:
1、copy:需要遵守NSCopying協議,實現copyWithZone:方法。
@protocol?NSCopying
- (id)copyWithZone:(NSZone?*)zone;
@end
2、mutableCopy : 需要遵守NSMutableCopying協議,實現mutableCopyWithZone:方法
@protocol?NSMutableCopying
- (id)mutableCopyWithZone:(NSZone?*)zone;
@end
只有源對象和副本對象都不可變時,才是淺復制,其他都是深復制。
深復制和淺復制的區別:
1.深復制(深拷貝、內容拷貝、deep copy):
特點:1、源對象和副本對象是不同的兩個對象;
2、源對象引用計數器不變,副本對象計數器為1(因為是新產生的)。
本質:產生了新對象。
2.淺復制(淺拷貝、指針拷貝、shallow copy):
特點:1、源對象和副本對象是同一對象;
2、源對象(副本對象)引用計數器+1,相當于做一次retain操作。
本質:沒有產生新對象。
淺拷貝:對象開辟新的空間,對象的內存地址不同,實例變量指向同一塊內存
- (id) copyWithZone:(NSZone*)zone
{
Person*p = [[Person allocWithZone:zone] init];
p.string=self.string;
return p;
}
深拷貝:對象和實例變量的內存地址都不同
- (id) copyWithZone:(NSZone*)zone
{
Person*p1 = [[Person allocWithZone:zone] init];
p1.string= [self mutableCopy];
return p1;
}
偽拷貝:
- (id) copyWithZone:(NSZone*)zone
{
return[self retain];
}
附、ARC的特點總結:
(1)不允許調用release,retain,retainCount
(2)允許重寫dealloc,但是不允許調用[super dealloc]
(3)@property的參數:
Strong:相當于原來的retain(適用于OC對象類型),成員變量是強指針
Weak:相當于原來的assign,(適用于oc對象類型),成員變量是弱指針
Assign:適用于非OC對象類型(基礎類型)
補充
讓程序兼容ARC和非ARC部分。轉變為非ARC? -fno-objc-arc? 轉變為ARC的, -f-objc-arc 。
ARC也需要考慮循環引用問題:一端使用retain,另一端使用assign。
提示:字符串是特殊的對象,但不需要使用release手動釋放,這種字符串對象默認就是autorelease的,不用額外的去管內存。
永遠不要在初始化方法使用self形式的代碼調用本類的方法,因為此時本類的方法可能未初始化完成,調用可能會發生crash,但是父類的方法可以調用,因為父類已經初始化完成,調用不會發生問題。
轉載請注明:作者SmithJackyson