天天看點

黑馬程式員-OC記憶體管理(一)手動管理記憶體(二)自動管理記憶體

------Java教育訓練、Android教育訓練、iOS教育訓練、.Net教育訓練、期待與您交流! -------

(一)手動管理記憶體

棧:存放局部變量(所占用記憶體會自動銷毀) -> 指向堆空間

堆:存放對象(所占用記憶體需手動銷毀)

管理範圍:所有繼承NSObject的類對象

1.記憶體洩露?記憶體洩露的後果?

_age = [age ratain];
           

自己申請的記憶體,沒有釋放 會使記憶體中存在很多的垃圾,浪費不必要的記憶體

2.應用計數器:用于計算對象被使用的次數,是一個整數(每個對象都有自己的引用計數器:占4個位元組) 

(1)當使用alloc、new或copy建立新對象時,新對象的引用計數器被設定為1.

(2)當引用計數器為0時,則此對象所占用記憶體就會被回收。(發送release消息時,計數器減1)

(3)給對象發送retainCount消息擷取目前的計數器值

   注:retain方法傳回的是對象本身(有傳回值)

3.對象的銷毀

(1)引用計數器為0,對象占用的記憶體被系統收回。(對象變成僵屍對象。指向此方法的指針值變為0)

(2)當對象被銷毀時,系統會自動向對象發送dealloc消息。(對象遺言)

(3)一般要重寫dealloc方法。(必須調用super的dealloc)

eg:

- (void)dealloc
{
       [super dealloc];
}
           

4.概念

(1)野指針:指向僵屍對象(不可用記憶體)的指針。

注:給野指針發送消息會報錯,報錯提示:EXC_BAD_ACCESS

(2)僵屍對象:所占用記憶體已經被回收的對象,僵屍對象不能再使用、

(3)空指針:沒有指向任何東西的指針(存儲的東西是nil、NULL、0)

注:給空指針發送消息不會報錯

5.記憶體管理原則:

(1)當想使用(占用)某個對象時,就應該讓對象的計數器+1 (讓對象做一個ratain操作)

eg:

_age = [age ratain];
           

(2)當不想使用(占用)某個對象時,就應該讓對象的計數器-1 (讓對象做一次release操作) 

eg:

-(void)dealloc
{ 
        [_dog release];//對象計數器-1
        [super dealloc];
}
           

(3)誰retain,誰release;誰alloc,誰release。

注:對象在set方法中指派時,應該進行一次retain操作。(基本資料類型不需要管理記憶體 )

6.set方法記憶體管理

(1)隻要調用了alloc,則必須要有release(或autorelease);

如果對象不是通過alloc産生,則不需要release。

(2)set方法代碼規範

1)基本資料類型:直接指派(基本資料類型不需要進行記憶體管理)

eg:

- (void)setAge:(int)age
{
   _age = age; 
}
           

2)OC對象類型

eg:

- (void)setCar:(Car *)car
{
   if ( car != _car) // 1.先判斷是不是新傳進來的對象
   {
      [_car release]; // 2.對舊對象做一次release
      _car = [car retain]; //  3.對新對象做一次retain
   }                             
}
           

(3)dealloc代碼規範

1>一定要有[super dealloc],而且要放到最後。

2>對self(目前)所擁有的其他對象做一次release

eg:

- (void)dealloc
{
    [_car release]; // 一旦Person release,則車也應該release
    [super dealloc]; // 這段一定要放最後
}
           

[email protected] 記憶體管理

@property (參數) 對象

eg :

@property (nonatomic,retain) Car *car;
           

(1)set方法記憶體管理的相關參數

retain:生成的setter方法中會release舊值,retain新值。(适用于OC對象類型)

assin:直接指派(預設,适用于非OC對象類型)

copy: release舊值,copy新值。

(2)是否要生成set方法

readwrite:可讀寫,同時生成setter和getter的聲明、實作(預設)

readonly:隻讀,隻會生成getter的聲明、實作。

(3)多線程管理(多個線程同時調用某個方法)

nonatomic:代表方法不要考慮線程安全性問題,告訴系統不在set方法中生成多線程代碼。(高性能,禁止多線程,推薦使用)

atomic:代表給方法進行加鎖,保證線程安全(預設,低性能)

線程保護機制:防止方法在未寫入完成時,被其它線程調用,造成資料錯誤。

(4)setter和getter方法的名稱

setter:setter = 方法名,決定了set方法的名稱,方法名一定有冒号:

getter:決定了get方法的名稱。(一般用在BOOL類型)

8.循環retain和@class

1>(1)@class使用方法:

作用: @class Card 僅僅告訴編譯器,Card隻是一個類

使用場合:用于.h聲明此類,但是不會引入此類的方法和成員變量。

注意點:僅僅聲明這個類,不會将此類的方法和成員變量導入,如果需要,則應該在.m檔案中#import此類。

(2)引用一個類的規範

1>在.h頭檔案中用@class來聲明類

2>在.m源檔案中用#import來包含類的所有東西

(3)@class優點

1>解決循環包含的問題。- >隻在.m 源檔案中進行引用(可以循環聲明,A中聲明B,B中聲明A)

2>提高了性能。->如果被引入類的頭檔案進行了修改,不需要全部進行重新編譯。

(4)@class 和 #import 差別

1> #import方式會包含被引用類的所有資訊,包括被引用類的變量和方法;(使用類所有資訊,包括成員變量和方法)

@class方式隻是告訴編譯器在A.h檔案中 ,聲明某個類,不知道此類的所有具體資訊。(僅僅聲明有這個類)

2>如果有上百個頭檔案都#import了同一個檔案,那麼一旦被導入檔案的頭檔案稍有改動,後面引用到這個 

檔案的所有類的頭檔案都需要重新拷貝,效率較低。(A->B,B->C,C->D.....一旦A變動,則後面都需要重新編譯。程式隻編譯.h檔案)

使用@class方式就不會出現這種問題了,隻需在源檔案中修改類即可,提高了效率。

(解決了循環包含問題)

3>在.m實作檔案中,如果需要引用到被引用類的成員變量或方法時,還需要使用#import方式引入被引用類。

2> 兩端循環引用解決方法(循環retain)

一端用retain,一端用assign。、

eg: Car 端 : @property (nonatomic,retain) Person *person;

Person端:@propertor (nonatomic,assign) Car *car

9. autorelease

eg: Person *p = [[[Person alloc] init] autorelease]; //必須存在釋放池,才能寫autorelease

作用:1>autorelease會将對象放到一個自動釋放池中,當自動釋放池被銷毀時,會對池子裡所有對象做一次release。

2>傳回對象本身,且不影響對象計數器。

注:池子被銷毀時,對象不一定會被銷毀,隻是做一次release。釋放池内可嵌套釋放池

eg:

int main()
{
    @autoreleasepool
    { // { 代表開始建立釋放池

    } // } 代表銷毀釋放

}
           

優點:1>不用在關心對象釋放的時間.

2>不需要關心什麼使用調用release。

缺點:不能精确控制對象銷毀時間。

使用注意:1>占用記憶體較大的對象不要随便使用autorelease(不能精确控制對象銷毀時間)

2>占用記憶體較小的對象使用,則不會有太大影響。

建議:盡量使用release,因為可以精确控制對象銷毀。

使用規範:1>系統自帶的方法中,如果不包含alloc、new、copy,那麼這些方法傳回的對象都是已經autorelease的

2>開發中經常寫一些類方法快速建立一個autorelease的對象。(不使用類名,使用self)

eg:

+ (id)Person  
{  
    return [[[self alloc] init] autorelease];  
}  
           

(二)自動管理記憶體

自動回收記憶體機制。

優點:不需要人為添加記憶體管理代碼,提高了程式設計效率與安全性。

1.概念:編譯器會自動在适當的地方插入适當的retain、release、autorelease語句。(屬于編譯器特性)

2.ARC的判斷标準:

隻要沒有強指針指向對象,就會釋放對象。

eg: Person *p = [[Person alloc] init];

p = nil;

代碼解析:預設情況下,p是強指針。當p等于空時,就沒有強指針指向Person對象,這時候編譯器會自動将Person對象銷毀。

(1)強指針:預設情況下,指針都是強指針(__strong)

(2)弱指針: __weak 修飾

eg: __weak Person *p2 = p ; (p2就是個弱指針)

3. ARC特點:

(1)不允許手工調用release、retain、autoretain。

(2)允許重寫dealloc,但是不允許調用[super dealloc];

(3)@property參數

strong:成員變量是強指針,相當于以前retain(使用OC對象)

weak:成員變量是弱指針,相當于以前assign(使用OC對象)

assign:基本資料類型,直接指派。(使用非OC對象)

(4)以前的retain,全部改為strong,其餘不變

eg: @property (nonatomic,retain) Car *car;

改為:@property (nonatomic,strong) Car *car;

4.某.m檔案不需要ARC方法

不需要ARC: 添加-fno-objc-arc

黑馬程式員-OC記憶體管理(一)手動管理記憶體(二)自動管理記憶體

   需要ARC:-f-objc-arc

5.解決循環引用問題

1>ARC

一端用strong,一端用weak

eg:  Dog 端 : @property (nonatomic,strong) Person *person;

Person端:@propertor (nonatomic,weak) Dog *car

黑馬程式員-OC記憶體管理(一)手動管理記憶體(二)自動管理記憶體

2>非ARC

一端用retain,一端用assign

eg: Dog 端 : @property (nonatomic,retain) Person *person;

Person端:@propertor (nonatomic,assign) Dog *car

6.總結

ARC最大的優點就是極大的提高了程式編寫效率,開發者不需要關心對象的銷毀時間,不需要擔心程式的記憶體洩漏問題

繼續閱讀