OC的內(nèi)存管理
開始之前, 先思考一個(gè)問(wèn)題:為什么要管理內(nèi)存?
曾看到一個(gè)笑話, 一個(gè)程序員去面試iOS程序員,面試官問(wèn):iOS開發(fā)中為什么需要內(nèi)存管理?
程序員淡定地說(shuō):內(nèi)存有限,所以要管理內(nèi)存啊.
答案很出乎意料,但是仔細(xì)想想,真是一語(yǔ)道破了本質(zhì).
那在內(nèi)存有限的情況下, 為什么要管理內(nèi)存呢?
在iOS開發(fā)中, 我們要保證有限的內(nèi)存資源得到最大化的利用,當(dāng)我們創(chuàng)建一個(gè)類的對(duì)象時(shí), 對(duì)應(yīng)的在內(nèi)存中,就得到一個(gè)塊內(nèi)存來(lái)存放這個(gè)對(duì)象的內(nèi)容. 但是這個(gè)對(duì)象(或者理解成一塊內(nèi)存), 可能被多個(gè)指針變量使用. 不要奇怪, 怎么又出現(xiàn)了指針變量. 這是因?yàn)?在objective-C中,我們都是通過(guò)對(duì)象的引用來(lái)操縱內(nèi)存的. 它本質(zhì)就是一個(gè)指針(該對(duì)象在內(nèi)存中的地址). 這樣做的好處是快呀. 試想, 我們?cè)陂_發(fā)中, 同一個(gè)對(duì)象可能被次使用, 如果直接操作對(duì)象本身,那么當(dāng)我們把一個(gè)對(duì)象賦值給另一個(gè)對(duì)象的時(shí)候,就需要把該對(duì)象中的所有內(nèi)容全部都挨個(gè)從該對(duì)象所在的內(nèi)存中取出來(lái),放到另外一塊內(nèi)存中. 如果,我們使用一個(gè)對(duì)象的地址來(lái)使用對(duì)象,那么就僅僅把一個(gè)整形值賦值給另外一個(gè)對(duì)象的引用就OK了.
-
說(shuō)了那么多,看一下內(nèi)存的布局:
可執(zhí)行文件在內(nèi)存中的布局
現(xiàn)在我們知道內(nèi)存管理實(shí)際上是管理我們的對(duì)象,對(duì)于其他的非對(duì)象類型不需要內(nèi)存管理(int,float,,,)
這是為什么呢?
這是因?yàn)?堆區(qū)需要程序員手動(dòng)管理, 棧區(qū)內(nèi)存由系統(tǒng)負(fù)責(zé)管理(申請(qǐng)和釋放).實(shí)際上,非對(duì)象類型的數(shù)據(jù)內(nèi)容和對(duì)象類型的數(shù)據(jù)內(nèi)容,一個(gè)放在棧里面,一個(gè)放在堆里面(這里暫時(shí)這么理解:其實(shí)和變量是否靜態(tài)以及是否是全局有關(guān)系), 本質(zhì)上我們管理內(nèi)存就是管理堆. 即便后來(lái)objective-C退出的ARC機(jī)制,也僅僅是為每個(gè)對(duì)象添加一個(gè)自己的引用計(jì)數(shù)器.(作用是記錄有多少"人"在使用它,或者說(shuō)有多少指針在指向這塊內(nèi)存),當(dāng)我們創(chuàng)建對(duì)象,對(duì)象之間相互傳值的時(shí)候, 系統(tǒng)自動(dòng)的加減引用計(jì)數(shù)的值代替程序員手動(dòng)的管理內(nèi)存.
注意:有些時(shí)候, 文中所指的對(duì)象和對(duì)象引用(指針)為同一概念, 但是對(duì)象的本質(zhì)是對(duì)應(yīng)堆區(qū)中的一塊內(nèi)存這一點(diǎn)是不變的
回到主題:為什么要管理內(nèi)存呢?不好回答. 我們可以取反唄, 如果不管理內(nèi)存會(huì)怎么樣?
- 如果內(nèi)存不管理, 那么手機(jī)中的內(nèi)存資源將會(huì)被很快的用完.
- 如果內(nèi)存得不到很好的管理, 可能會(huì)出現(xiàn)正在使用的對(duì)象,但是該對(duì)象所對(duì)應(yīng)的內(nèi)存已經(jīng)被系統(tǒng)釋放,甚至已被分配給別的對(duì)象. 造成野指針,甚至數(shù)據(jù)錯(cuò)誤的現(xiàn)象.
- 如果內(nèi)存得不到很好的管理,可能會(huì)出現(xiàn). 對(duì)象已經(jīng)沒有被使用了,但還沒有被釋放. 浪費(fèi)內(nèi)存.
- 如果內(nèi)存得不到很好的管理,還會(huì)出現(xiàn)很多問(wèn)題...
既然要管理內(nèi)存,就是要避免出現(xiàn)以上情況
如何管理內(nèi)存
objective-C中通過(guò)引用一個(gè)叫做引用計(jì)數(shù)器的機(jī)制,來(lái)管理內(nèi)存. 它的作用就是記錄當(dāng)前對(duì)象(一塊內(nèi)存)在程序中,有多少"人"在使用它.或者說(shuō)有多少指針正在指向它.如果,仍然有指針在指向這塊內(nèi)存,而此時(shí)我們卻釋放了這塊內(nèi)存,這時(shí)候,該指針就成野指針了.
管理內(nèi)存需要遵循的一些原則:
- 自己生成的對(duì)象自己持有
- 非自己生成的對(duì)象自己也能持有
- 不在需要自己持有的對(duì)象時(shí)釋放
- 非自己持有的對(duì)象不能釋放
在objective-C中都提供一些,供我們持有和釋放以及銷毀內(nèi)存的方法供程序員使用,以便需要的時(shí)候,調(diào)用對(duì)應(yīng)的方法來(lái)恰當(dāng)?shù)墓芾韮?nèi)存.
- (instancetype)retain OBJC_ARC_UNAVAILABLE;
- (oneway void)release OBJC_ARC_UNAVAILABLE;
- (instancetype)autorelease OBJC_ARC_UNAVAILABLE;
- (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE;
+ (instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
- (void)dealloc OBJC_SWIFT_UNAVAILABLE("use 'deinit' to define a de-initializer");
分別對(duì)應(yīng)下面的內(nèi)存管理動(dòng)作:
- 生成并持有 alloc ,new, copy等方法
- 持有 retain
- 釋放 release
- 銷毀 dealloc
在OC中通過(guò)alloc類方法,可以生成一個(gè)對(duì)象.也可以通過(guò)使用Copy,mutableCopy 來(lái)生成一個(gè)對(duì)象的副本. 返回一個(gè)指向這個(gè)對(duì)象的指針 , 這個(gè)對(duì)象是保存在內(nèi)存中的堆區(qū)的, 可以通過(guò)一個(gè)相同類型的指針變量來(lái)接收這個(gè)指針,從而使用它.但是這個(gè)指針變量是存儲(chǔ)在棧區(qū)的. 不需要管理, 系統(tǒng)會(huì)在"必要的時(shí)刻" 彈出棧幀, 這個(gè)時(shí)候,這個(gè)指針變量所指向的內(nèi)存會(huì)release.
生成并持有的使用場(chǎng)景:

到了總結(jié)的時(shí)候了:也就是說(shuō),objective-C中的內(nèi)存管理,管理的是內(nèi)存中堆區(qū)中存放的對(duì)象,通過(guò)為每個(gè)對(duì)象增添一個(gè)引用計(jì)數(shù)器來(lái)實(shí)現(xiàn), 我們需要根據(jù)代碼中有多少引用指向該對(duì)象來(lái)動(dòng)態(tài)的增加(向?qū)ο蟀l(fā)送retain消息)和減少(向?qū)ο蟀l(fā)送release消息)引用計(jì)數(shù)器的值.
對(duì)于上文中所提到的內(nèi)存管理需要遵循的原則沒有詳細(xì)說(shuō)明:打算下一篇在ARC中說(shuō)明.
