OC 的內存管理

OC 的內存管理

一、 基本原理

1. 什麼是內存管理

移動設備的內存及其有限,每個app所能佔用的內存是有限制的;

當app所佔用的內存較多時,系統會發出內存警告,這時得回收一些不需要在使用的內存空間,比如回收一些不需要使用的對象;

管理範圍:任何繼承了NSObject的對象,對其他基本數據類型(int char float double struct enum等)無效;

2. 對象的基本結構

每個OC對象都有自己的引用計數器,是一個整數,表示“對象被引用的次數”, 即有多少人正在使用這個OC對象;

每個OC對象內部專門有4個字節的存儲空間來存儲引用計數器;

當對象剛被創建的時間 存儲計數器默認值爲1;

3. 引用計數器的作用

當使用alloc、new或者copy創建一個新對象時,新對象的應用計數器默認就是1

當一個對象的引用計數器值爲0時,對象佔用的內存就會被系統回收,換句話說,如果對象不爲0,那麼在整個程序運行過程,他佔用的內存就不可能被回收,除非整個程序已經退出

4. 引用計數器的操作

給對象發送一條relain消息,可以使用計數器值+1(relain方法返回對象本身);

給對象發送一條release消息,可以使用引用計數器-1

可以給對象發送一條retainCount消息獲得當前的引用計數器的值

5. 對象的銷燬

當一個對象的引用計數器值爲0時,那麼他將被銷燬,其佔用的內存被系統回收;

當一個對象被銷燬時,系統會自動向對象發送一條dealloc消息;

一般會重寫dealloc方法,在這裏釋放相關資源,deallic就像對象的遺言;

一旦重寫了dealloc方法,就必須調[superdealloc],並且放在最後面調用

不要直接調用dealloc方法;

一旦對象被回收了,它佔用的內存空間就不再可用,堅持使用會導致程序崩潰(野指針錯誤);

【野指針:指向殭屍對象(不可用內存)的指針】【EXC_BAD_ACCESS:訪問了一塊壞的內存(已經被回收、已經不可用的內存),也稱爲:野指針錯誤    解決方法:p=nil 清空指針

OC中不存在空指針錯誤;

【messagesent to deallocated instance 0*100109a10】

【給已經釋放的對象發送了一條-setAge消息:】

【如果對象已經變成殭屍對象之後不能ratain方法】

6.方法的基本使用

a)  Retain:計數器+1 ,返回值是對象本身;

b)  Release : 計數器+1,沒有返回值;

c)  retainCount :獲取當前的計數器的值;

d)  dealloc

l  當一個對象被回收的時候,就會調用;

l  一定要調用[super dealloc];這句調用要放在最後面;

7.部分概念

a)  殭屍對象:所佔有內存已經被回收的對象,殭屍對象不能再使用;

b)  野指針:指向殭屍對象(不可用內存)的指針,給野指針發送消息會報錯;

c)  空指針:沒有指向任何東西的指針(存儲的東西是nil、0),給空指針發送消息不會報錯;

二、 內存管理原則

1.  原則分析

l  QQ糖開房間原理:只要房間還有人在用就不會解散

l  只要還有人在用某個對象,那麼這個對象就不會被回收

l  只要你想用這個對象,就讓對象的計數器+1

l  當你不再使用這個對象時,就讓計數器-1

2.  誰創建,誰release

l  如果你通過alloc、new或[mutable]copy來創建一個對象,那麼你必須調用release或者autorelease;

l  換句話說,不是你創建的,就不用你去[auto]release;

3.  誰retain,誰release

l  只要你調用了retain,無論這個對象是如何生成的,你都要調用release;

4.  總結

l  有始有終,有加就有減;

l  曾經讓對象的計數器+1,就必須在最後讓對象計數器-1;

三、  set方法的內存管理

如果你有個oc對象類型的成員變量,就必須管理這個成員變量的內存。比如有個Book *_book

內存管理代碼規範:

1.只要調用alloc,必須有release(autorelease)

2.set方法的代碼規範

1> 基本數據類型:直接複製

-(void)setAge:(int)age

{

     _age=age;

}

2>OC對象類型

-(void)setCar:(Car *)car

{

  //先判斷是不是薪傳進來對象

if( car !=_car)

{

     [_car release];

     _car = [car retain];

}

}

3>dealloc方法代碼規範

1.  一定要[super dealloc],而且放到最後面

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

-(void)dealloc

{

   [_carrelease];

   [superdealloc];

}

4>@property內存管理

@property (retain) Bool  *book;

@property中的參數

1) 內存管理相關的參數

retain :release舊值,retain新值(適用於OC對象類型)

assign:直接賦值(默認,適用於非OC對象類型)

copy   :release舊值,copy新值

2)是否要生成set方法

    readonly  :只會聲明get的聲明和實現

  readwrite :同時生成set和get的聲明和實現

3)多線程管理

    nonatomic :性能高(一般就用這個)

    atomic    :性能低(默認)

4)set和get方法的名稱:

    getter= 方法名;一般用於BOOL類型的數值

    setter= 方法名;(一定要記住“:”)

四、 循環引用

@class

1.@class的作用:僅僅告訴編譯器某個名稱是一個類

@class Person //僅僅告訴編譯器Person是一個類

2.開發中引用一個類的規範

a) .h文件中用@class來聲明類

b) 在.m文件中用#import來包含類的所有東西

3.【面試題】

@class 和#import的區別

#import方法會包含被引用類的所有信息,包括被引用類的變量和方法;@class方法只是告訴編譯器在A.h文件中B *b只是類的聲明,具體這個類裏面有什麼信息,這裏不需要知道,等實現文件中真正要用到時,纔會真正去查看B類中信息

如果有上百個頭文件都用#import了同一個文件,或者這些文件依次被#import那麼一旦最開始的頭文件稍有改動,後面引用到這個文件的所有列都需要重新編譯一遍,這樣的效率也是可想而知的,而相對來講,使用@class方式就不會出現這種問題了

在.m實現文件中,如果需要引用到被引用類的實體變量或者方法時,還需要使用#import方式引入被引用類

【面試題】循環引用的解決方法:

兩端循環引用解決方案:

一端用retain,一端用assign

五、autorelease方法:半自動釋放

Person *p = [[[Person alloc] init] autorelease];

autorelease方法返回對象本身

調用autorelease方法後,對象的計數器不變

autorelease會將對象放到一個自動釋放池中

當自動釋放池被銷燬時,會對池子裏面的所有對象做一次release操作

@autoreleasepool

{

//傳說中的自動釋放池的創建

    //自動釋放池可以創建無限多個

    //不能精確控制釋放時間

}

@autorelease的基本用發

A.會將對象放到一個自動釋放池中

B.當自動釋放池被銷燬時,會對池子裏面的所有對象做一次release操作

C.會返回對象本身

D.調用完autorelease方法後,對象的計數器不變

@autorelease的優點

A.不用在關心對象釋放的時間

B.不用在關心什麼時候調用release

@autorelease的使用注意

A.佔用內存較大的對象不要隨便用autorelease

B.佔用內存較小的對象使用autorelease沒有太大的影響

【面試題】:

情況一:autoreleasepool{

Person *p = [[[Person alloc]init]autorelease]

[p release];

}

情況二:Person*p = [[[[Person alloc] init]autorelease]autorelease]

這種連續調用多次autorelease就會出現野指針錯誤

自動釋放池

A.在ios程序運行過程中,會創建無數個池子。這些池子都是以棧結構存在(先進後出)

B.當一個對象調用autorelease方法時,會將這個對象放到棧頂的釋放池

Ios 5.0 之前的釋放池格式

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

[pool release];//[pool drain]此釋放用於mac

IOS5.0之後的釋放池格式

@autoreleasepool

{

}

 

1.系統自帶的方法裏面沒有包含alloc、new、copy,說明返回的對象都是autorelease的

2.開發中經常會提供一些類方法,快速創建一個已經autorelease方法

a)  創建對象時不要直接用各類名,一般用self

+person

{

   Return[[[selfalloc] init] autorelease];

}

六、 ARC

Arc 的判斷標準:只要沒有強指針指向對象,就會釋放對象

 

指針分2 種:

1.強指針:默認情況下,所有指針都是強指針

2.弱指針:__weak

在arc中retain換成strong

總結

1.ARC特點

a)  不允許調用release、retain、ritainCount

b)  允許重寫dealloc,但是不允許調用[superdealloc]

c)  @property的參數

l  strong : 成員變量是強指針,相當於原來的retain(適用        於OC對象類型)

l  weak:成員變量是弱指針,相當於原來的assign(適用於OC 對象類型)

l  assign:適用於非OC對象類型

d)  以前的retain改爲strong ,其他的一切不變

Refactor 重構

ARC的轉換 xcode菜單  Edit-----Refactor-----轉換成ARC

 

單獨處理非ARC文件轉換  -fno-objc-arc

轉換成ARC文件  -f-objc-arc

ARC的循環引用:

一端用strong一端用weak

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章