開發iPhone 應用程序并不難,基本上就是三個詞 - “memory, memory, memory” 。iPhone OS 對內存的要求很嚴格,有memory leak ,殺掉; 內存使用超限額,殺掉。一個經過測試的程序,在使用過程中90%以上的崩潰都是內存問題造成的。在這里簡單總結一下Object-C 內存管理。
基本概念
Object-C 的內存管理基于引用計數(Reference Count)這種非常常用的技術。簡單講,如果要使用一個對象,并希望確保在使用期間對象不被釋放,需要通過函數調用來取得“所有權”,
函數
獲得所有權的函數包括
alloc - 創建對象是調用alloc,為對象分配內存,對象引用計數加一。
copy - 拷貝一個對象,返回新對象,引用計數加一。
retain - 引用計數加一,獲得對象的所有權。
另外,名字中帶有alloc, copy, retain 字串的函數也都認為會為引用計數加一。
釋放所有權的函數包括
release - 引用計數減一,釋放所有權。如果引用計數減到零,對象會被釋放。
autorelease - 在未來某個時機釋放。下面具體解釋。
autorelease
在某些情況下,并不想取得所有權,又不希望對象被釋放。例如在一個函數中生成了一個新對象并返回,函數本身并不希望取得所有權,因為取得后再沒有機會釋放(除非創造出新的調用規則,而調用規則是一切混亂的開始),又不可能在函數內釋放,可以借助autorelease 。所謂autorelease , 可以理解為把所有權交給一個外在的系統(這個系統實際上叫autorelease pool),由它來管理該對象的釋放。通常認為交給 autorelease 的對象在當前event loop 中都是有效的。也可以自己創建NSAutoreleasePool 來控制autorelease的過程。
據蘋果的人說,autorelease效率不高,所以能自己release的地方,盡量自己release,不要隨便交給autorelease來處理。
規則
引用計數系統有自己的引用規則,遵守規則就可以少出錯:
獲得所有權的函數要和釋放所有權的函數一一對應。
保證只有帶alloc, copy, retain 字串的函數才會讓調用者獲得所有權,也就是引用計數加一。
在對象的 dealloc函數中釋放對象所擁有的實例變量。
永遠不要直接調用dealloc來釋放對象,完全依賴引用計數來完成對象的釋放。
有很多類都提供“便利構造函數(convenience constructors)”,它們創建對象但并不增加引用計數,意味著不需要調用release來釋放所有權。很好辨認,它們的名字中不會有alloc和copy。
只要遵守這些規則,基本上可以消除所有Intrument可以發現的內存泄露問題。
容器
類似NSArray, NSDictionary, NSSet 等類,會在對象加入后引用計數加一獲得所有權,在對象被移除或者整個容器對象被釋放的時候釋放容器內對象的所有權。類似的情況還有UIView對 subview的所有權關系,UINavigationController對其棧上的controller的所有權關系等等。
其他所有權的產生
還有一些用法會讓系統擁有對象的所有權。比如NSObject 的performSelector:withObject:afterDelay 。如果有必要,需要顯示的調用cancelPreviousPerformRequestsWithTarget:selector:object: ,否則有可能產生內存泄露。
因這種原因產生的泄露因為并不違反任何規則,是Intrument所無法發現的。
新聞熱點
疑難解答