天天看點

IOS有關記憶體管理的二三事

随着移動裝置的記憶體越來越大,程式員也已經度過了為了那一兩m的記憶體在系統的抽絲剝繭的年代,對于java的開發者,對記憶體更是伸手即取,并且從不關心什麼時候還回去。但是,程式的掌控度對程式員來說是至關重要的,任何語言的記憶體管理機制的初衷也是在有限的空間裡完成最精緻的邏輯。

arc是xcode5中引入的自動引用計數,其原理與mrc是一樣,隻是系統幫助我們添加了retain和release。現在在xcode中建立的項目預設都是arc的環境,我們可以通過設定其為mrc。

在buildsettings中搜尋arc:

IOS有關記憶體管理的二三事

将下面的參數設定為no,預設是yes。

IOS有關記憶體管理的二三事

這時項目工程的環境就變成了mrc。

現實中的許多舊的項目,還有一些比較老的第三方庫,可能都是采用mrc環境編寫的,我們在對其進行擴充或者做新項目的相容的時候,可以在xcode中對其進行混編。

選擇:target->build phases->compile sources

IOS有關記憶體管理的二三事

如果工程是arc,要混編mrc的檔案,我們選中compiler flags,後面設定為-fno-objc-arc

如果工程是mrc,要混編arc檔案,我們在後面設定-fobjc-arc

無論你是隻注重于代碼邏輯,将記憶體交給arc的新時代程式員,還是依然對apple的信任不足,依然事必躬親的mrc古闆程式員,我想你都應該了解ios中記憶體管理的機制,盡管arc機制很成熟也很可靠,可是依然會有很多應用存在循環應用,記憶體洩露等問題,要知道,arc不是萬能的,它僅僅隻是幫你省去寫一些繁瑣的代碼。

首先,在object-c中建立對象傳回的并不是對象本身,而是一個指針。比如我們使用alloc申請空間,會經常這樣做:

uiimage * image = [[uiimage alloc]init];

這裡,調用的alloc時,系統将給我們建立的類配置設定一塊記憶體空間,并傳回一個指向這個空間的指針。調用init時對對象進行初始化。如果此時,我們将image這個指針置為nil:image=nil;那樣将造成記憶體洩露,系統配置設定給image的空間永遠無法回收。是以,在我們不需要image這個對象時,我們會使用dealloc方法将其交還給系統:[image dealloc];然而這裡,有将産生一個嚴重的問題,如果我們此時列印image的指針,會發現它現在成了一個危險東西,因為它指向的東西不存在了,而它卻依然指向那個地方,這便是很多程式員的噩夢:野指針。為此,我們應該養成一個好習慣,不用的指針置為nil,所有對空指針進行的操作都被認為是安全的。

通過上面的了解,我們發現了一個非常麻煩的地方,我申請了一塊記憶體空間,如果我将指針置空了而沒有釋放對象,則會記憶體洩露,如果我提前釋放了對象,又很可能會有野指針的出現。并且如果有很多類都引用了這個對象,我甚至的不知道我應該什麼時候釋放它。是以,object-c為我們引入了引用計數這種管理記憶體的方法,任何引用這個對象的地方,都應該讓這個對象的引用計數加1。同樣,任何不再需要這個對象的地方,也應該使它的引用計數減1,如此一來,對象記憶體便被統一的管理了起來。

引用計數記憶體管理的機制是對象的計數,每個對象至少會有一個引用者,如果沒有了引用者,對象會被釋放。

黃金法則:

1、當你使用alloc,new,copy,mutablecopy建立對象時,你才需要管理他們。

2、你可以使用retain給一個對象增加引用計數。

3、當你不再需要一個對象時,你必須調用release減少其引用計數。

4、你不能釋放不屬于你的對象的所有權。

上面就是黃金法則的所有内容,我譯的可能不到位,總結為一點,也是至關重要的一點就是:誰建立了對象,誰釋放掉對象。誰增加了引用計數,誰就在不用時減少計數。alloc,new,copy,mutablecopy,retain這些方法會使引用計數增加,release會使引用計數減少,當計數為0時,系統會調用dealloc釋放記憶體。

為了友善記憶體管理,避免我們頻繁的調用release方法,object-c中還為我們引用了一種機制:自動釋放池。自動釋放池的原理其實隻是延時釋放,它并沒有幫我們做太多的工作。自動釋放池的使用方式有兩種:

1、mrc時:

<a href="http://my.oschina.net/u/2340880/blog/411930#">?</a>

1

2

3

<code>    </code><code>nsautoreleasepool * pool = [[nsautoreleasepool alloc]init];</code><code>//建立一個自動釋放池,系統預設會為我們建立一個,我們也可以建立自己的。</code>

<code>    </code><code>uiimage * image = [[[uiimage alloc]init] autorelease];</code><code>//在池内建立一些對象,會和最近的自動釋放池比對</code>

<code>    </code><code>[pool release];</code><code>//這時自動釋放池會向池子中的每一個對象發送release消息</code>

2、arc時:

<code>  </code><code>@autoreleasepool {</code>

<code>        </code><code>uiimage * image = [[[uiimage alloc]init] autorelease];</code>

<code>    </code><code>}</code>

<code></code>