IPhone上木有垃圾回收,動態申請的內存要自己記得釋放,此文自己總結一下可能出現內存洩露的各種情況,以及檢測方法。
內存洩露說白了,就是有這樣一塊動態申請的內存,但木有任何一個指針指向它。
舉例來說,在C++中:
1. MyClass * foo = new MyClass;
2. foo = NULL;
類似地在objective-C中:
1. MyClass *foo = [[MyClass alloc] init];
2. foo = nil;//內存洩露了!
或者有這樣一個類:
1. @interface Foo : NSObject
2. {}
3. @end
4.
5. @implementation Foo
6. -(id) init
7. {
8. if ((self = [super init])) {
9. NSMutableString * string = [[NSMutableString alloc] initWithString:@"Leaker!!!"];
10. string = nil;//洩露了!這句之後那個字符串對象應用退出之前不會被釋放。
11. }
12. return self;
13. }
14. - (void) dealloc
15. {
16. [super dealloc];
17. }
18. @end
出現內存洩露會怎樣?
答:很小的洩露,沒事!應用退出的時候所用內存都會被清理,包括洩露的,而且IPhone應用不會申請到共享內存,不會波及到整個系統,不會出現系統范圍的內存洩露。要是洩露的比較多,而且反復不停地出現內存洩露,頂多應用崩潰掉。不過想發布到AppStore的話,有內存洩露一般會被蘋果拒絕……。
先來看看IPhone裡內存是怎麼管理的,首先:木有自動垃圾回收!其次:有引用記數!
NSObject對象有個屬性:retainCount,所以所有對象都要繼承自NSObject,才有統一的引用計數…。
然後牢記記住下面8件事:
• 1 這個retainCount == 0的時候,對象的dealloc方法會被調用,對象就被釋放了。
• 2 永遠不要顯示調用dealloc方法
• 3 [obj retain]; // obj.retainCount++ 引用記數+1
• 4 [obj release]; // obj.retainCount-- 引用記數-1
• 5 MyClass * obj = [[MyClass alloc] init];// obj.retainCount = 1 初值為1
• 6 對於有retain特性的屬性比如下面這個:
1. @interface MyClass : NSObject {
2. NSObject* foo;
3. }
4. @property (noatomic,retain) NSObject * foo;
5. @end
6.
7. @implementation MyClass
8. @synthesize foo;
9. ...
10. //下面兩行正確的寫法
11. self.foo = bar;// [foo release]; foo = bar; [foo retain]; 會發一個release給原來的對象,發一個retain 給新對象
12. self.foo = nil;// [foo release]; 會發一個release 消息給對象
13.
14. //下面一行寫法不對
15. foo = bar;// 沒發release給foo 沒發retain給bar ,這種寫法是不對的。
16. ...
17. @end
參考:
蘋果的文檔 和 具體實現的解釋
• 7 對於stringWithString 這種方法創造的對象,一個Runloop結束時,對象會被發送一個release消息,需要注意的有兩點,一是注意理解Runloop,避免Runloop結束後對象被釋放了卻又使用對象,二是 如果用instruments工具檢測內存洩露,這種使用autorelease的情況也會被當做內存洩露處理,注意識別……。
• 8 對於NSMutableArray這種類,當addObject的時候,相應被加入array中的那個對象的引用計數會被+1,當array本身釋放時,它會先給array中的所有對象發一個release消息。www.2cto.com
可以用Instruments檢測內存洩露,裡各種各樣的工具,用Leaks。
用起來很簡單:用Xcode(4.3)打開相應的項目,Product->Profile,選Leaks工具。 之後會動態地記錄應用運行過程中,有哪些地方出現內存洩露。 需要注意的地方有二:
1 對於被autorelease的對象,Leak工具也會視其為洩露,自己知道沒問題就行。
2 記得點開Extended Detail ,對於每一出洩露,可以在這裡看到調用堆棧,雙擊調用堆棧中的某一項,可以直接定位到代碼,便於查錯跟修改。 情況如下兩個圖:
作者:dawn110110