2012-12-26 46 views
7

我有內存泄漏內存泄漏使用ConcurrentQueue時:與ConcurrentQueue

requestObject request = xxx; 

Item obj= new Item(); 
obj.MessageReceived += obj_MessageReceived; 
obj.Exited += obj_Exited; 

request.Key = obj.Key; 

obj.AddRequest(request); 

_queue.TryAdd(obj.Key, obj); 

在「已退出」的回調,我處置資源:

void LiveSphere_Exited(string key) 
{ 
    Item instance; 

    _queue.TryRemove(key, out instance); 

    Task.Factory.StartNew(() => 
    { 
     var wait = new SpinWait(); 
     while (instance.MessageCount > 0) 
     { 
      wait.SpinOnce(); 
     } 
    }) 
    .ContinueWith((t) => 
    { 
     if (instance != null) 
     { 
      //Cleanup resources 
      instance.MessageReceived -= obj_MessageReceived; 
      instance.Exited -= obj_Exited; 
      instance.Dispose(); 
      instance = null; 
     } 
    }); 
} 

當我分析代碼,我仍然有一個引用了「Item」對象的根,但我不知道我可以在哪裏處理..., 已激活的方法被觸發,並且_queue已從隊列中刪除了「Item」對象。

當我閱讀文檔時,concurrentqueue將引用複製到隊列中。

你能幫我找出內存泄漏是什麼?

+5

不知道你的內存泄漏的地方。 「ConcurrentQueue」的.NET 4.0版本中存在內存泄漏,但已修復爲4.5。你可能會考慮研究'BlockingCollection',這是一個更好的併發集合包裝。默認行爲在內部使用'ConcurrentQueue'。 –

+0

我不願意調用.NET 4的'ConcurrentQueue'漏洞 - 主要是這種情況只發生在你沒有使用它的情況下(直到有多個項目被彈出時它纔會將數據設置爲null) - 在這種情況下,ConcurrentQueue的意義何在? –

+0

謝謝吉姆,但我已經在.NET 4.5中,我需要FIFO隊列,阻塞集合是FIFO? – dnx

回答

6

與標準.NET隊列不同,調用Dequeue()不會從集合中刪除對該對象的引用。儘管此行爲已從4.0版本更改爲4.5版本(我已閱讀此內容,但尚未對其進行測試),但這不是一個錯誤,而是框架團隊做出的有意識的設計決策,作爲設計線程安全的一部分,可枚舉集合。

This article有更多信息,包括通過使用StrongBox來包裝進入ConcurrentQueue的對象的解決方法。這應該是一個合適的解決方法,直到你可以轉向4.5框架。

+2

考慮到它的結果,我稱之爲「有意識的設計錯誤」。 – hypersw

+0

我已經嘗試過這種StrongBox方法,但只是延遲了這個問題。內存仍然增加到約1.7GIG,那麼該應用程序有延遲問題和崩潰。 – user2520306

1

我看過併發隊列的實現。有些情況下隊列將在Dequeue()被調用後持有對該對象的引用。

併發隊列使用段來存儲數據。在那裏,它是該段的TryRemove方法的一部分:

// If there is no other thread taking snapshot (GetEnumerator(), ToList(), etc), reset the deleted entry to null. 
// It is ok if after this conditional check m_numSnapshotTakers becomes > 0, because new snapshots won't include 
// the deleted entry at m_array[lowLocal]. 
if (m_source.m_numSnapshotTakers <= 0) 
{ 
    m_array[lowLocal] = default(T); //release the reference to the object. 
} 

所以,當你有一個不同的線程,在你出列的對象的對象引用不會被設置爲空,同時列舉了隊列。

相關問題