Objective-C 記憶體管理,
管理範圍:任何繼承NSObject的對象,基礎資料型別 (Elementary Data Type)不用進行管理
本質原因:因為對象和基礎資料型別 (Elementary Data Type)在系統中的儲存空間不一樣,局部變數主要存放在棧中,而Object Storage Service於堆中,當代碼塊結束時這個代碼塊中涉及的所有局部變數會被回收,指向對象的指標也被回收,此時對象已經沒有指標指向,但依然存在於記憶體中,造成記憶體泄露。
出現原因:
1.記憶體溢出:沒有指向對象的指標,但是對象沒有被回收
2.野指標異常:指向殭屍對象的指標,殭屍對象是記憶體被回收的對象。
給null 指標發送訊息不會報錯
在每個oc對象內部,都有專門的4個位元組的儲存空間來儲存引用計數
記憶體管理方式:
1.手工引用計數(manual reference counting)
2.自動引用計數(auto reference counting)
MRC的記憶體管理機制:引用計數
ARC是基於MRC的,ARC是編譯器特性,而不是運行時特性
記憶體管理原則
(一)原則
只要還有人在使用某個對象,那麼這個對象就不會被回收;
只要你想使用這個對象,那麼就應該讓這個對象的引用計數器+
1
;
當你不想使用這個對象時,應該讓對象的引用計數器-
1
;
(二)誰建立,誰release
(1)如果你通過alloc,
new
,copy來建立了一個對象,那麼你就必須調用release或者autorelease方法
(2)不是你建立的就不用你去負責
(三)誰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的,不用額外的去管記憶體。