iOS中的內存管理(上)

    下列行爲都會增長一個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;
相關文章
相關標籤/搜索