iOS開發中的內存管理機制淺談
iOS開發中的有關內存管理
一、前引
隨著移動設備的內存越來越大,程序員也已經度過了為了那一兩M的內存在系統的抽絲剝繭的年代,對于JAVA的開發者,對內存更是伸手即取,并且從不關心什么時候還回去。但是,程序的掌控度對程序員來說是至關重要的,任何語言的內存管理機制的初衷也是在有限的空間里完成最精致的邏輯。
二、Xcode工程設置ARC
ARC是xcode5中引入的自動引用計數,其原理與MRC是一樣,只是系統幫助我們添加了retain和release。現在在xcode中新建的項目默認都是ARC的環境,我們可以通過設置其為MRC。
在BuildSettings中搜索ARC:
將下面的參數設置為NO,默認是YES。
這時項目工程的環境就變成了MRC。
三、項目中實現MRC和ARC混編
現實中的許多舊的項目,還有一些比較老的第三方庫,可能都是采用MRC環境編寫的,我們在對其進行擴展或者做新項目的兼容的時候,可以在xcode中對其進行混編。
選擇:target->build phases->compile sources
如果工程是ARC,要混編MRC的文件,我們選中compiler flags,后面設置為-fno-objc-arc
如果工程是MRC,要混編ARC文件,我們在后面設置-fobjc-arc
四、IOS內存管理機制基本原理
無論你是只注重于代碼邏輯,將內存交給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時:
1
2
3
|
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc]init]; //創建一個自動釋放池,系統默認會為我們創建一個,我們也可以創建自己的。 UIImage * image = [[[UIImage alloc]init] autorelease]; //在池內創建一些對象,會和最近的自動釋放池匹配 [pool release]; //這時自動釋放池會向池子中的每一個對象發送release消息 |
2、ARC時:
1
2
3
|
@autoreleasepool { UIImage * image = [[[UIImage alloc]init] autorelease]; }
|