2012-12-06 42 views
0

我是Objective-C的初學者。 我正在通過編寫簡單的命令行代碼研究Objective-C中的內存管理。Objective-C 2.0的內存管理

我的環境如下。

  • Mac OS X Mountain Lion。
  • Xcode4.5

我寫了下面的代碼。

test.m

1  #import <Foundation/Foundation.h> 
2  #import <stdio.h> 
3  
4  @interface A : NSObject 
5  -(void)myprint; 
6  @end 
7  
8  @implementation A 
9  -(void)dealloc { 
10  printf("dealloc!!\n"); 
11  [super dealloc]; 
12 } 
13  
14 -(void)myprint { 
15  printf("myprint!!\n"); 
16 } 
17 @end 
18  
19 int main(void) { 
20  
21  id obj1 = [[[NSObject alloc] init] autorelease]; 
22  id obj2 = [[A alloc] init]; 
23  
24  [obj2 release]; 
25  [obj2 myprint]; 
26  
27  return 0; 
28 } 

我建立這個代碼如下命令。(不帶ARC選項編譯)

clang -g -Wall -o main test.m -fno-objc-arc -framework Foundation 

構建成功,沒有任何警告信息。 結果如下。

dealloc!! 
myprint!! 

我對這個結果有兩個問題。

第一個問題是關於自動釋放方法。 我認爲這段代碼會引發運行時錯誤,因爲 autorelease方法在沒有NSAutoreleasePool實例的情況下被調用。 爲什麼這段代碼不會引發運行時錯誤?

第二個問題是關於dealloc方法。 obj2在調用dealloc方法後響應myprint方法。 爲什麼在調用dealloc方法之後obj2響應myprint方法?

謝謝。

+0

另外 - 我建議您專注於使用Xcode和Instruments,因爲它們在擴展您的項目方面要好得多。 – bbum

回答

2

第一個問題是關於自動釋放方法。我認爲這段代碼會導致運行時錯誤 ,因爲調用autorelease方法時沒有使用 NSAutoreleasePool實例。爲什麼這段代碼不會產生運行時 錯誤?

沒有自動釋放池,因此,我看不到的沒有游泳池到位警告運行時有點驚訝。這不會是一個錯誤,但只是一個運行時警告,發生泄漏。

奇數。我看到了同樣的行爲。我會問。

第二個問題是關於dealloc方法。在調用dealloc方法後,obj2響應myprint 方法。爲什麼在調用dealloc方法之後,obj2會響應 myprint方法?

未定義的行爲。 obj2已被釋放,但釋放並不意味着內存已被清除。

如果打開的malloc塗鴉(其中塗鴉上釋放內存),你會看到預期的崩潰:

env MallocScribble=1 ./main 
dealloc!! 
Segmentation fault: 11 

更重要的是,如果你打開的殭屍檢測:

env NSZombieEnabled=YES ./main 
dealloc!! 
2012-12-06 08:10:14.580 main[80114:f07] *** -[A myprint]: message sent to deallocated instance 0x7f9b7ac09dd0 
Trace/BPT trap: 5 
+0

+1爲您的超級解釋。 –

+0

很好的答案!你的回答對我很有幫助。謝謝。 –

2

我相信一個autorelease池會自動創建,但我可能是錯的。至於第二部分,我的理解是釋放告訴一個對象停止被保留,所以它不能保證在釋放消息之後的任何時候仍然存在,但是這可能會持續一段時間,直到該內存塊被用於別的東西。基本上你很幸運,如果你再次運行你的代碼,你可能並不總是每次都有obj2響應myprint。

+0

否... autorelease池未創建。因爲你可以在我的答案中看到附加的圖像。 –

+0

這種情況下沒有autorelease池。剩下的答案几乎是正確的;該對象已被釋放,但釋放並不意味着該字節立即被重用。打開殭屍,你會得到一個錯誤。 – bbum

+0

啊,謝謝你對autorelease池的澄清。 – LighteningKid

1

我想同樣的,你可以看到發生了什麼:

正如你可以看到沒有自動釋放池...調試器顯示泄漏。

enter image description here

編輯:

我做研究,才知道,這釋放工作,但系統需要時間來釋放,直到下一次,然後打印語句被調用。你可以用下面的代碼檢查:

A *obj2 = [[A alloc] init]; 


NSLog(@"1rc=%ld",[obj2 retainCount]); 

[obj2 release]; 

for (long i=0; i<1000000; i++) { 
    for (long j=0; j<10000; j++) { 
     ; 
    } 
} 


[obj2 myprint]; 


for (long i=0; i<1000000; i++) { 
    for (long j=0; j<10; j++) { 
     ; 
    } 
} 
NSLog(@"myprint again"); 
[obj2 myprint]; 
+0

那些for循環是沒有意義的。沒有線程?完全線性執行,包括對象的釋放和釋放。您從未定義的行爲中得出錯誤的結論。 – bbum

+0

我被困在這裏,即使我問了數十種可可資源(同事),沒有人能夠給出一個很好的理由。所以最後這個結論。這個問題仍然存在。這真的是一個很好的學習。我正在等待更正,並附有證明。 –

+0

我嘗試了與Xcode相同的代碼。沒有出現關於autorelease的警告消息。但我明白,調用沒有池的autorelease方法會調用內存泄漏。 –