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