Objective-C 內存管理

結論:誰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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 前言 之前的兩篇拙文C語言-內存管理基礎、C語言-內存管理深入 介紹了關于C語言在內存管理方面的相關知識。但是對于...
    老板娘來盤一血閱讀 3,775評論 25 36
  • 1.1 什么是自動引用計數#### 顧名思義,自動引用計數(ARC,Automatic Reference Cou...
    見哥哥長高了閱讀 604評論 0 1
  • 內存管理的問題# ??先看看下面的幾段代碼,重溫一下使用內存常見的問題。 ??C語言中內存操作常見錯誤: 內存分配...
    DeanYan閱讀 1,031評論 0 1
  • 內存管理是程序在運行時分配內存、使用內存,并在程序完成時釋放內存的過程。在Objective-C中,也被看作是在眾...
    蹲瓜閱讀 3,197評論 1 8
  • 內存管理 簡述OC中內存管理機制。與retain配對使用的方法是dealloc還是release,為什么?需要與a...
    丶逐漸閱讀 2,013評論 1 16