2017-02-16 49 views
0

我的macOS應用程序遭受嚴重的內存泄漏。經過大量調試後,我似乎找到了原因,但我仍然不太明白。macOS:由setNeedsDisplayInRect導致的內存消耗

該應用程序將像素繪製到內部緩衝區,然後實際將其繪製到NSView子類的drawRect方法中。重繪由[self setNeedsDisplayInRect:rect]觸發。

幾個小時後,程序消耗了幾千兆字節的RAM。但是,當我把電話setNeedsDisplayInRect放在一個循環中來調用它時,比如說每10,000次(而不是僅僅一次)重新繪製時,內存消耗在幾分鐘內就會上升到千兆字節。

爲了確保內存不在drawRect方法中泄漏,我刪除了整個主體,只留下一個空方法。

據筆者所知,所有給予setNeedsDisplayInRect的指令都被存儲起來,直到在下一輪事件循環中實際處理重繪爲止。所以當我稱它爲10,000次時,我預計內存消耗會更高,但我不希望它會一直保持上升 - 我預計在事件循環的一次迭代之後,所有存儲的rects將被清除。

那麼,爲什麼調用setNeedsDisplayInRect時內存的數量會持續上升?我知道每秒鐘多次調用10000次並不是正常使用,但在正常情況下,內存使用量也會持續增長,但速度要慢很多。

代碼摘錄:

- (void)drawRect:(NSRect)dirtyRect { 
// Currently, nothing happening 
} 

// My own method, that gets called from elsewhere. 
- (void) drawToScreen:(int) x : (int) y : (int)w :(int)h :(int *)data 
{  
    int rectYPos = MAX(height - y - h, 0); 
    NSRect rect = NSMakeRect(x, rectYPos, w, h); 
    for(int i = 0; i < 10000; i++) 
    { 
     [self setNeedsDisplayInRect:rect]; 
    } 
} 

回答

1

如果你從一二級/後臺線程調用這個,你可能要檢討(從蘋果公司的文檔):

「如果一個應用程序的輔助線程想要在主線程中重繪視圖的某些部分,但不能使用像display,setNeedsDisplay:,setNeedsDisplayInRect:或setViewsNeedDisplay:這樣的方法來實現。相反,它應該向主線程發送消息或調用這些方法改爲使用performSelectorOnMainThread:withObject:waitUntilDone:方法。「

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/ThreadSafetySummary/ThreadSafetySummary.html

+0

這確實看起來是問題所在。奇怪的是,這沒有記錄在setNeedsDisplay *文檔中。我用'dispatch_async(dispatch_get_main_queue(),^(void){[self setNeedsDisplayInRect:rect];});' ...替換了'[self setNeedsDisplayInRect:rect]',現在內存不再泄漏。也就是說,它仍然緩慢上升,但一段時間後突然下降;重複。 – Mathijs