2010-11-13 71 views
3

下面的代碼循環不會泄漏內存(通過觀察它在無限循環下「top」)來驗證;objc泄漏行爲我無法解釋

NSBitmapImageRep *this_bmap = 0; 

while (1) { 

    CGImageRef windowImage = 
    CGWindowListCreateImage(CGRectNull, 
          kCGWindowListOptionIncludingWindow, 
          windowID, kCGWindowImageDefault); 

    this_bmap = [[NSBitmapImageRep alloc] initWithCGImage:windowImage]; 

    [this_bmap release]; 
    CGImageRelease(windowImage); 
} 

我不會期待它。然而,當我複製一個指針位圖數據,像這樣:

NSBitmapImageRep *this_bmap = 0; 

while (1) { 

    CGImageRef windowImage = 
    CGWindowListCreateImage(CGRectNull, 
          kCGWindowListOptionIncludingWindow, 
          windowID, kCGWindowImageDefault); 

    this_bmap = [[NSBitmapImageRep alloc] initWithCGImage:windowImage]; 

    void *pixels1 = [this_bmap bitmapData]; 

    [this_bmap release]; 
    CGImageRelease(windowImage); 
} 

這現在泄漏像瘋了似的。我可以看到這種情況在「最高層」下迅速發生,該計劃最終陷入停滯。

我是新來的Objective-C,但我不是新手編程,我無法理解這種行爲。方法bitmapData的文檔聲明它只是返回一個指針(而不是分配內容),所以我很難過。我從前一段時間發現了一個類似的問題,但唯一的答案是「調查泳池」,但我不明白這對此有何幫助。

任何想法這裏發生了什麼?

回答

0

嗯,我不是大師,所以我只是猜測在這裏。但是對我而言,每次進行循環時,您都會有效地聲明一個名爲pixels1的新變量。因此,每次通過你分配一些新的空間,而不是重複使用它。嘗試移動循環外的像素1的聲明並查看會發生什麼。

請注意,這只是一個猜測,可能是錯誤的。一個更有知識的人可能會給你一個明確的答案。

+1

貌似我錯了:-) – drekka 2010-11-13 04:08:22

0

的「initWithCGImage:」電話有這樣的說明文件中:

討論

如果使用這種方法,你 應該把所生成位圖 NSBitmapImageRep對象爲只讀。 由於它只保留 中的值而不是 解包數據,因此需要在內存中創建該數據的 副本。對該數據的更改 不會保存回 核心圖形圖像。

這似乎表明從bitmapData返回的內存需要CFRelease'ed。

+1

不,因爲從bitmapData返回的指針不是CF對象。嘗試'CFRelease'會導致崩潰。 – 2010-11-13 06:17:35

7

訪問像素數據會導致對象被保留和自動釋放,以便位圖數據不會突然消失。若要查看您的預期結果(即循環不會消耗每次迭代的內存),請重新編寫爲:

NSBitmapImageRep * this_bmap = 0;

while (1) { 
    NSAutoreleasePool* loopPool = [NSAutoreleasePool new]; 
    CGImageRef windowImage = 
    CGWindowListCreateImage(CGRectNull, 
          kCGWindowListOptionIncludingWindow, 
          windowID, kCGWindowImageDefault); 

    this_bmap = [[NSBitmapImageRep alloc] initWithCGImage:windowImage]; 

    void *pixels1 = [this_bmap bitmapData]; 

    [this_bmap release]; 
    CGImageRelease(windowImage); 
    [loopPool drain]; 
} 
+0

這工作。我不明白,所以我有一些功課要做。非常感謝你。 – rwa 2010-11-13 04:30:33

+0

沒有太多的功課要做。當池被排空/釋放時,自動釋放的對象被放入池中以被釋放。這發生在運行循環中正在處理的每個事件結束時(即,一旦您的整個調用堆棧在接收事件後完成)。如果你有這樣一個緊密的循環,池會很快被填滿,直到整個循環(以及它後面的所有調用)完成之後纔會排空。爲循環的每次迭代創建和排空新的自動釋放池意味着池永遠不會變得如此之大。 – d11wtq 2010-11-13 06:02:29