天天看點

Objective-C記憶體管理

objective-c記憶體管理的三種方式:

1)自動垃圾收集(automatic garbage collection);

2)手動引用計數器(manual reference counting)和自動釋放池;

3)自動引用計數器(automatic reference counting)。

1、自動垃圾收集

    在oc2.0中,有一種自動垃圾收集的記憶體管理形式,通過垃圾自動收集,系統能夠自動檢測出對象是否擁有其他的對象,當程式運作期間,不被引用的對象就會自動釋放。

說明:在ios運作環境中不支援自動垃圾收集,在os x環境才支援,但是apple現在不建議使用該方法,而是推薦使用arc進行替代。

2、手動引用計數器(manual reference counting)和自動釋放池

    顧名思義,引用計數器即一個對象被引用(使用)的次數,每個對象的引用計數器占用4個位元組。

    影響對象rc值得方法有以下幾種:

1)new、alloc、copy、mutablecopy,這幾種方法用來建立一個新的對象并且獲得對象的所有權,此時rc的值預設為rc=1;

2)retain,對象調用retain方法,該對象的rc+1;

3)release,對象調用 release方法,該對象的rc-1;

4)dealloc,dealloc方法并不會影響rc的值,但是當rc的值為0時,系統會調用dealloc方法來銷毀對象。

    關于關于在mrc中@property關鍵字如下:

1)assign 和 retain 和 copy

這幾個關鍵字用于setter方法的記憶體管理,如果使用assign(一般用于非oc對象),那麼将直接執行指派操作;如果使用retain(一般用于oc對象),那麼将retain新值,release舊值;如果使用copy,那麼将release舊值,copy新值。不顯示使用assign為預設值。

2)nonatomic 和 atomic

這兩個關鍵字用于多線程管理,nonatomic的性能高,atomic的性能低。不顯示使用atomic為預設值。

3)readwrite 和 readonly 

這兩個關鍵字用于說明是否生成setter方法,readwrite将自動生成setter和getter方法,readonly 隻生成getter方法。不顯示使用readwrite為預設值。

4)getter 和 setter

這兩個關鍵字用于給設值和取值方法另外起一個名字。例如@property(getter=a,setter=b:) int age;相當于取值方法名為a,設值方法名為b:。

    對于兩個類a包含b,b包含a的循環引用情況下,隻需要在book1和book2的@property屬性聲明中一端使用retain,一端使用assign;或使用@class。

autorelease pool的使用注意點:

1)release方法不能多次調用,該調用的時候調用,否則容易造成野指針錯誤。

2)建立對象時多次調用autorelease方法,容易造成野指針錯誤。

3)在自動釋放池中新建立的對象并不是一定會添加到釋放池中,例如由new、alloc、copy、mutablecopy建立的對象并不會加到自動釋放池中,并且必須手動調用release方法才能釋放對象。如果想讓新建立的對象加入到自動釋放池中,就必須調用autorelease方法。

4)使用autorelease方法并不會使引用計數器的值增加,隻是表示将該對象加入到自動釋放池中。

3、自動引用計數器(arc)

    arc将由編譯器來自動完成對象引用計數器的控制,不需要手動完成。

    arc模式下,建立的新對象通常由以下幾種關鍵字來限定:

__strong(預設值),由__strong修飾的為強指針,對象隻要有強指針指向就不會被銷毀;每當一個強指針指向一個對象,該對象的的rc+1;

__weak,由__weak修飾的為弱指針,弱指針所指向的對象并不會改變rc值,弱指針隻表示是對對象的引用;當弱指針所指向的對象銷毀時,該弱指針的值變為nil;

__unsafe_unretained,__unsafe_unretained修飾的對象指針所指向的對象也不會改變rc值,也隻表示是對對象的引用;當所指向的對象銷毀時,該指針的值不會變為nil,仍是保留原有的位址;

    在arc模式下,mrc中的retain、release等方法變的不可用,因為arc是不需要我們手動管理記憶體的,一切由編譯器完成。

    在arc模式下,@property屬性關于記憶體管理的修飾符為strong和weak(mrc下的retain和assign不可用),表示聲明為強指針還是弱指針。通常情況下都是使用strong來修飾,但是在循環引用卻不是。

    在互相引用的兩個類中,為了避免循環引用,一般一端使用strong修飾,一端使用weak修飾。如果都使用strong修飾,那麼将造成對象的循環保持,造成記憶體洩露。

注意點:

1)arc模式下仍能使用自動釋放池;

2)mrc下的retain、release、retaincount、autorelease等方法不可使用。

3)注意循環引用下strong和weak的選擇。

附:常見記憶體管理問題

 1.什麼是ios記憶體管理?

   就是在對象不再被使用的時候,把它即時的從記憶體中清除掉

 2.為什麼要使用記憶體管理?

   1.嚴格的記憶體管理,能夠使我們的應用程在性能上有很大的提高

   2.如果忽略記憶體管理,可能導緻應用占用記憶體過高,導緻程式崩潰

 3.系統判斷一個對象是否要被銷毀的依據是什麼?

   每個對象建立出來的時候,都有一個retaincount屬性,預設值是1,當retaincount = 0的時候,系統就會将該對像銷毀

 4.如何使對象的retaincount 值增加?

   調用retain 對象方法

 5.如何使對象的retaincount 值減少?

   調用release 對象方法

 6.如何判斷對象已經被銷毀了?

   1.重寫nsobject提供的dealloc方法,當對象即将被銷毀的時候,預設會調用該方法

   2.dealloc方法中一定要調用[super dealloc]方法

 7.記憶體管理原則是什麼?

   誰申請,誰釋放;

   隻要是出現new,alloc,retain,就要配對出現release操作,或者autorelease操作

 **單個對象記憶體管理 問題

 1.什麼是野指針?

   對象的retaincount已經為0,儲存了對象指針位址的變量就是野指針

  1.1 使用野指針會有什麼問題?

      使用野指針調用對象的方法,會導緻野指針異常,導緻程式直接崩潰

 2.什麼是僵屍對象?

   retaincount = 0的對象被稱之為僵屍對象,也就是不能夠在通路的對象

   2.1是什麼問題導緻,通路僵屍對象,時而正确時而錯誤?

   2.2如何開始xcode的時時檢測僵屍對象功能?

 3.如何防止出現野指針操作?

   通常在調用完release 方法後,會把儲存了對象指針位址的變量清空,指派為nil

   在oc中沒有空指針異常,是以使用[nil retain]調用方法不會導緻異常的發生

 4.什麼是記憶體洩漏?

   已經不在使用的對象,沒有正确的釋放掉,一直駐留在記憶體中,我們就說是記憶體洩漏

 5.記憶體洩漏有幾種情況?

    1.沒有配對釋放,不符合記憶體管理原則

    2.對象提前指派為nil或者清空,導緻release方法沒有起作用

 6.當對象的retaincount = 0 時 能否調用 retain方法使對象複活?

   已經被釋放的對象是無法在複活的

 7.關于記憶體我們主要研究的問題是什麼?

   1.野指針

   2.記憶體洩露

**多個對象記憶體管理 問題

 1.對象與對象之間存在幾種關系?

   1.繼承關系

   2.組合關系

   3.對象作為方法參數傳遞

 2.對象的組合關系中,如何確定作為成員變量的對象,不會被提前釋放?

   重寫set方法,在set方法中,retain該對像,使其retaincount值增加 1

 3.組合關系導緻記憶體洩漏的原因是什麼?

   在set方法中,retain了該對象,但是并沒有配對釋放

 4.作為成員變量的對象,應該在那裡配對釋放?

   在dealloc函數中釋放

** set方法記憶體管理 問題

 1.在對象的組合關系中,導緻記憶體洩漏有幾種情況?

   1.set方法中沒有retain對象

   2.沒有release掉舊的對象

   3.沒有判斷向set方法中傳入的是否是同一個對象

 2.該如何正确的重寫set方法?

   1.先判斷是否是同一個對象

   2.release一次舊的對象

   3.retain新的對象

**記憶體管理@property參數 問題

 1.@property參數分為幾類?

  1.與set方法記憶體管理相關的參數

  2.是否要生成set方法相關

  3.多線程相關

  4.set和get方法的名稱相關

 2.@property參數那些适用于對象類型,那些适用于基本資料類型

 3.如何使用@property生成符合記憶體管理的set方法?

 4.@property retain參數能否用于基本資料類型?

 不能

**手動記憶體管理類的循環引用 問題

 1.什麼情況下會出現類的循環應用?

 2.@class關鍵子的作用?

 3.手動記憶體管理如何解決類的循環引用問題?

 4.在.h檔案中使用@class關鍵字聲明一個類後,在.m檔案中是否能夠直接掉用該對象的方法?

**自動釋放池 問題

1.什麼是自動釋放池?

  自動釋放池是用來存儲多個對象類型的指針變量

2.自動釋放池對池内對象的作用?

  被存入到自動釋放池内的對象,當自動釋放池被銷毀時,會對池内的對象全部做一次release操作

3.對象如何放入到自動釋放池中?

 當你确定要将對象放入到池中的時候,隻需要調用對象的 autorelease 對象方法就可以把對象放入到自動釋放池中

4.如何建立自動釋放池?

對象在自動釋放池内部調用autorelease 方法

5.自動釋放池能否嵌套使用?

6.自動釋放池何時被銷毀?

在autorelease } 執行完後

7.多次調用對象的autorelease方法會導緻什麼問題?

多次将位址存到自動釋放池中,導緻野指針異常

8.自動釋放池作用

将對象與自動釋放池建立關系,池子内調用autorelease 方法,在自動釋放池銷毀時銷毀對象,延遲release銷毀時間

**自動釋放池應用 問題

 1.實際開發中一般如何使用autorlease

就是在方法中建立新的對象并且需要傳回的時候

快速建立一個類方法

**arc機制 問題

 1.什麼是arc機制

   自動引用計數,不需要程式員關心,對象的retain,與release操作

 2.什麼是強指針(strong),弱指針(weak)

預設情況下,一個指針都會使用 __strong 屬性,表明這是一個強引用。這意味着,隻要引用存在,對象就不能被銷毀。這是一種所期望的行為:當所有(強)引用都去除時,對象才能被收集和釋放。

不過, 有時我們卻希望禁用這種行為:一些集合類不應該增加其元素的引用,因為這會引起對象無法釋放。在這種情況下,我們需要使用弱引用(不用擔心,内置的集合類 就是這麼幹的),使用 __weak 關鍵字。nshashtable 就是一個例子。當被引用的對象消失時,弱引用會自動設定為 nil。

    1.(weak與strong)不同的是:當一個對象不再有strong類型的指針指向它的時候,它就會被釋放,即使改對象還有_weak類型的指針指向它;

    2.一旦最後一個指向該對象的strong類型的指針離開,這個對象将被釋放,如果這個時候還有weak指針指向該對象,則會清除掉所有剩餘的weak指針

 3.arc機制中,系統判斷對象是否被銷毀的依據是什麼?

指向對象的強指針是否被銷毀

 4.arc機制中,如何觀察對象被銷毀了?

 5.arc機制中為什麼還有autoreleasepool?

arc 并不是舍棄了 @autoreleasepool,而是在編譯階段幫你插入必要的 retain/release/autorelease 的代碼調用。

是以,跟你想象的不一樣,arc 之下依然是延時釋放的,依然是依賴于 nsautoreleasepool,跟非 arc 模式下手動調用那些函數本質上毫無差别,隻是編譯器來做會保證引用計數的正确性。

 6.arc機制的本質是什麼?

對releasecount的計算,建立對象 +1, 清空指針 -1,或者越到autoreleasepool的大括号 -1

7.arc的目的

是讓程式員不在關心對象的retaincount

**arc機制 @property參數 問題

 1.arc機制中如何讓@property生成符合記憶體管理的set方法

 2.@property weak參數能否用于基本資料類型?

不能

 3.為什麼在arc機制中,不建議使用assign類表示對象的直接指派

4.arc機制中不建議使用retain,assign ,容易造成混淆

(1)strong還是weak

    說到底就是一個歸屬權的問題。小心出現循環引用導緻記憶體無法釋放,或者需要引用的對象過早被釋放。大體上:iboutlet可以為weak,nsstring為copy或strong,delegate一般為weak,基礎類型用assign,不過要注意具體使用情況。

(2)outlet使用strong還是weak

    官方文檔建議一般outlet屬性都推薦使用weak,不是直接作為main view裡面一個subview直接顯示出來,而是需要通過執行個體化建立出來的view,應該使用 strong(自己建立的自己當然要保持引用了)。但是要注意使用 weak時不要丢失對象的所有權,否則應該使用strong。

(3)delegate使用strong還是weak

    delegate主要涉及到互相引用和crash(引用被釋放)問題,為了防止這兩個問題發生,delegate一般使用weak。

**手動記憶體管理代碼轉換成arc代碼 問題

 1.如何使用xcode自帶的功能,将手動記憶體管理代碼轉換成arc機制代碼

 手動記憶體管理與arc機制代碼共存 問題 

 1.為什麼會出現手動記憶體管理與arc機制代碼共存現象?

 2.為什麼不統一的将代碼都轉換成arc機制?

 3.如何才能夠讓手動記憶體管理的代碼與arc機制的代碼共存?

**arc機制中類的互相引用 問題

 1.arc機制中類的互相引用,與手動記憶體管理類的互相引用有什麼差別嗎?

 2.如何解決arc機制下類的互相引用問題?

在.h檔案中使用@class關鍵字聲明一個類,兩端不能都用強指針

一端用strong,一端用weak

不要直接調用dealloc,我們知道dealloc中一般處理對象的釋放,該方法的調用一般是由系統在類銷毀時或記憶體不足時調用。因為系統知道類何時被銷毀。如果手動釋放,該類可能被其它類引用,這時在嘗試通路時就成造成系統崩潰。

繼續閱讀