注:本文為筆記形式,所以很多都是摘抄的.<<iOS 與OS X多線程和內(nèi)存管理>>書中寫的很棒,簡單易懂,建議各位看官自己去看看.
前言
知其然而不知所以然,一向是開發(fā)人員所忌諱的.其實(shí)對于iOS的多線程和內(nèi)存管理,當(dāng)時學(xué)習(xí)iOS的時候就已經(jīng)學(xué)習(xí)過了相關(guān)技術(shù)了,但是呢,隨著工作的時間加長用的卻是內(nèi)存管理以及多線程越是越來不明白了,正應(yīng)了開頭的那句話,所以到春季這段時間,我都會以<<iOS 與OS X多線程和內(nèi)存管理>>這本書為基礎(chǔ),內(nèi)存管理,block和GCD的使用進(jìn)行講解說明,這一篇我們就說一下關(guān)于iOS中內(nèi)存管理機(jī)制-引用計數(shù).
內(nèi)存管理的基礎(chǔ)概念
我們都知道,內(nèi)存管理分為五個區(qū),分別是棧區(qū),堆區(qū),靜態(tài)區(qū),常量區(qū),代碼區(qū),每個區(qū)都有著自己的特點(diǎn)(具體可查看華山論劍之iOS內(nèi)存,內(nèi)存管理,copy(拷貝)),我們要知道我們內(nèi)存管理的是內(nèi)存中的堆區(qū),在Xcode4.2之前,Object-C采用的是MRC(手動引用計數(shù))機(jī)制,而在其之后,Object-C采用的是ARC(自動引用計數(shù))機(jī)制.雖然我們現(xiàn)在很多時候用不到MRC機(jī)制,但是我們需要在MRC機(jī)制下運(yùn)行代碼了解程序猿在程序中是如何手動進(jìn)行內(nèi)存管理的.
對象的生成妇押、持有、釋放敲霍、廢棄
在<<iOS 與OS X多線程和內(nèi)存管理>>書中對于引用計數(shù)說到了以下的幾個說法.接下面,我們就對這幾個說法進(jìn)行一一的說明.
- 自己生成的對象,自己持有.
- 非自己生成的對象,自己也能持有.
- 不再需要自己持有的對象時釋放.
- 非自己持有的對象無法釋放.
那么,對象的生成、持有潭袱、釋放锋恬、廢棄這幾種方式在OC中都是如何表現(xiàn)的,看下表我們先大體粗略的了解一下.(這里我們不會相對autorelease
方法進(jìn)行詳細(xì)說明,請看本篇autorelease
模塊)
對象操作 | OC對應(yīng)方法 |
---|---|
生成并且持有對象,引用計數(shù)從0變?yōu)? |
alloc 、new 彤悔、copy 、mutableCopy 等 |
持有對象,引用計數(shù)+1 |
retain 方法 |
釋放對象,引用計數(shù)-1 |
release 方法 |
廢棄方法 |
dealloc 方法 |
自己生成的對象,自己持有
使用alloc
晕窑、new
卵佛、copy
、mutableCopy
這幾種方式就說明自己生成的對象,并且自己持有.我們在實(shí)際開發(fā)過程中接觸到alloc
疾牲、new
比較多,copy
、mutableCopy
是的比較少.
alloc
方法是我們經(jīng)常用來創(chuàng)建對象的方法,使用alloc
方法retainCount(引用計數(shù))為1,并且返回對象的指針.使用示例如下所示.
//obj的引用計數(shù)為1
id obj = [[NSObject alloc]init];
new
方法和alloc
方法類似,也能生成并且持有對象.并且retainCount(引用計數(shù))為1.示例如下所示.
//obj的引用計數(shù)為1
id obj = [NSObject new];
copy
和mutableCopy
這兩個方法都是生成并且持有對象的副本,兩者的不同之處在于copy
生成的是不可變的對象,mutableCopy
生成的則是可變對象.具體的示例如下所示.
id obj = [NSObject new];
//copyObj的引用計數(shù)為1
id copyObj = [obj copy];
//mutableCopyObj的引用計數(shù)為1
id mutableCopyObj = [obj mutableCopy];
非自己生成的對象,自己也能持有
我們先看下面書中的例子,以alloc
阳柔、new
舌剂、copy
、mutableCopy
等方法之外的方法取得的對象,因為不是自己生成并且持有的,所以自己并不是對象的持有者,(請注意這是MRC環(huán)境下)
id obj = [NSMutableArray array];
上面的代碼中,NSMutableArray對象被賦值給變量obj,但是變量obj卻并沒有持有該對象,我們需要使用retain
方法讓obj持有對象.這時候,NSMutableArray的引用計數(shù)為2.如下所示.
[obj retain];
有人會問為什么引用計數(shù)是2,這是因為NSMutableArray對象被創(chuàng)建的時候,引用計數(shù)為1,然后經(jīng)過retain方法操作之后,NSMutableArray對象的引用計數(shù)+1,所以為2.
不在需要自己持有的對象時釋放
當(dāng)我們持有的對象不再需要的時候,我們需要對持有對象進(jìn)行釋放.釋放的方式使用release
這個方法實(shí)現(xiàn),這個方法會使對象的引用計數(shù)減一,如果引用計數(shù)為0的話,系統(tǒng)會自己調(diào)用delloc
方法來釋放對象.示例如下所示.
NSMutableArray * obj = [NSMutableArray array];
[obj retain];
[obj release];
無法釋放非自己持有的對象
上面一塊我們說到持有的對象,我們有義務(wù)釋放,但是我們不能釋放自己沒有持有的對象,如果自己沒有持有對象而且強(qiáng)行釋放,那么應(yīng)用程序會發(fā)生崩潰.比如,
NSMutableArray * obj = [NSMutableArray array];
[obj retain];
[obj release];
[obj release];
autorelease
在MRC中,autorelease的使用大大的降低了我們代碼的復(fù)雜度和錯誤率,它看起來很像ARC,但是實(shí)際上它類似于C語言的局部變量.這里我們不得不說NSAutoreleasePool這個類,這個類是我們經(jīng)常提到的自動釋放池.我們每一個程序中都存在一個Main函數(shù),這是程序的主入口,其中@autoreleasepool {}
就是一個自動釋放池.
NSAutoreleasePool對象類似于C語言的作用域,對象的創(chuàng)建和釋放之間就是作用域.NSAutoreleasePool對象釋放掉之后,它所對應(yīng)的作用域里面的對象也會釋放掉.
接下來,我們看一下autorelease和NSAutoreleasePool對象是如何配合使用的.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
id obj = [[NSObject alloc]init];
[obj autorelease];
[pool drain];
前面,我們說到retain
和release
對引用計數(shù)的影響?那么調(diào)用autorelease
的對象,它的引用計數(shù)是怎么變化的呢?
對象執(zhí)行autorelease方法時會將對象添加到自動釋放池中 當(dāng)自動釋放池銷毀時自動釋放池中所有對象作release操作 對象執(zhí)行autorelease方法后自身引用計數(shù)器不會改變,而且會返回對象本身.autorelease實(shí)際上只是把對release的調(diào)用延遲了谴忧,對于每一次autorelease系統(tǒng)只是把該對象放入了當(dāng)前的autorelease pool中,當(dāng)該pool被釋放時,該pool中的所有對象會被調(diào)用Release委造。
結(jié)束
關(guān)于MRC以及引用計數(shù)相關(guān)的筆記就只有這么多了,建議各位看官自己去<<iOS 與OS X多線程和內(nèi)存管理>>,最后還是<<iOS 與OS X多線程和內(nèi)存管理>>的pdf版的下載傳送門,各位看官可以自行去參考查看.
<<iOS 與OS X多線程和內(nèi)存管理>>的PDF版?zhèn)魉烷T??