下列行爲都會增長一個app的內存佔用:
app
一、建立一個OC對象;
函數
二、定義一個變量;
spa
三、調用一個函數或者方法。
指針
若是app佔用內存過大,系統可能會強制關閉app,形成閃退現象,影響用戶體驗。如何讓回收那些再也不使用的對象呢?本文着重介紹OC中的內存管理。
code
所謂內存管理,就是對內存進行管理,涉及的操做有:
對象
一、分配內存:好比建立一個對象,會增長內存佔用;繼承
二、清除內存:好比銷燬一個對象,會減小內存佔用。
內存
內存管理的管理範圍:
資源
一、任何繼承了NSObject的對象;
it
二、對其餘非對象類型無效(int、char、float、double、struct、enum等)
只有OC對象才須要進行內存管理的本質緣由:
一、OC對象存放於堆裏;
二、非OC對象通常放在棧裏面(棧內存會被系統自動回收)
系統是如何判斷何時須要回收一個對象所佔用的內存呢?在這裏涉及到對象的「引用計數器」的概念。
引用計數器:
每一個OC對象都有本身的引用計數器,它是一個整數;每一個OC對象內部都有4個字節的存儲空間來存放引用計數器。
從字面上看,引用計數器能夠理解爲「對象被引用的次數」。
簡單來講,能夠理解爲:引用計數器表示有多少人正在使用這個對象。
當沒有任何人使用這個對象時,系統纔會回收這個對象;也就是說:
一、當對象的引用計數器爲0時,對象佔用的內存就會被系統回收;
二、若是對象的計數器不爲0,那麼在整個程序運行過程,它佔用的內存就不可能被回收(除非整個程序已經退出)。
任何一個對象,剛生下來的時候,引用計數器都爲1;當使用alloc、new或者copy建立一個對象時,對象的引用計數器默認就是1.
要想管理對象佔用的內存,就得學會操做對象的引用計數器。
引用計數器的常見操做:
一、給對象發送一條retain消息,可使引用計數器值+1(retain方法返回對象自己);
二、給對象發送一條release消息,可使引用計數器值-1;
三、給對象發送retainCount消息,能夠得到當前的引用計數器值。
須要注意的是:release並不表明銷燬\回收對象,僅僅是計數器值-1。
當一個對象的引用計數器值爲0時:
一、這個對象即將被銷燬,其佔用的內存被系統回收;
二、系統會自動給對象發送一條dealloc消息(所以,從dealloc方法有沒有被調用,就能夠判斷出對象是否被銷燬)。
dealloc方法的重寫;
一、通常會重寫dealloc方法,在這裏釋放相關資源,dealloc就是相關的遺言;
二、一旦重寫了dealloc方法,就必須調用[super dealloc],而且放在最後面調用。
使用注意:
一、不能直接調用dealloc方法;
二、一旦對象被回收了,它佔用的內存就再也不可用,堅持使用會致使程序崩潰(野指針錯誤)。
野指針\空指針概念:
殭屍對象:已經被銷燬的對象(不能再使用的對象)。
野指針:指向殭屍對象的指針;給野指針發消息會報「EXC_BAD_ACCESS」錯誤。
空指針:沒有指向存儲空間的指針(裏面存的時nil,也就是0);給空指針發消息是沒有任何反應的。
爲了不野指針錯誤的常見方法是:在對象被銷燬後,將指向對象的指針變爲空指針。
多對象內存管理規律:
單個對象內存管理比較簡單,若是對多個對象進行內存管理,而且對象之間是有聯繫的,那麼管理就會變得比較複雜;總的來講,多對象內存管理有幾點規律:
一、只要還有人在用某個對象,那麼這個對象就不會被回收;
二、只要你想用這個對象,就讓對象的計數器+1;
三、當你再也不使用這個對象時,就讓對象的計數器-1;
蘋果官方規定的內存管理原則:
一、誰建立誰release:若是你經過alloc、new或[mutable]copy來建立一個對象,那麼你必須調用調用release或autorrelease。
二、誰retain誰release:只要你調用了retain,就必須調用一次release。
總的來講就是:
一、有加就有減;
二、曾經讓對象的計數器+1,就必須在最後讓對象計數器-1.
set方法的內存管理以下:
- (void)setCar:(Car *)car { if (car != _car) { // 對當前正在使用的車(舊車)作一次release [_car release]; // 對新車作一次retain操做 _car = [car retain]; } }
dealloc方法的內存管理
- (void)dealloc { // 當人不在了,表明不用車了 // 對車作一次release操做 [_car release]; [super dealloc]; }
下面的代碼都會引起內存泄漏:
p.dog = [[Dog alloc] init]; [[Dog alloc] init].weight = 20.8;