2012-10-10 29 views
6

我使用Producer/Consumer PatternSystem.Collection.Concurrent.BlockingCollection<DataTable>從數據庫(生產者)檢索數據並在數據(消費者)上創建Lucene索引。.Net併發BlockingCollection有內存泄漏?

製作人一次抓取10000條記錄,並將添加到BlockingCollection<DataTable>。消費者(比較慢一點)然後抓住這10000個並創建一個索引。

阻塞集合的範圍是每行10000個行的5個<DataTable>

起初該程序運行良好,但在獲取大約150000行後,我注意到我的電腦內存已經超出,並且慢慢爬行。

看來,BlockingCollection無法在拍攝該項目後將底層陣列插槽設置爲null

代碼:

private static LuceneIndex index; 
    private static BlockingCollection<DataTable> blockingCol; 

    private static void Producer() 
    { 
     while (true) 
     { 
      //...get next 10000 rows 
      DataTable data = GetNextSet(); 
      if(data.Row.Count > 0) 
       blockingCol.Add(products); 
      else 
       break; 
     } 
    } 

    private static void Consumer() 
    { 
     while (!BlockingCol.IsCompleted || BlockingCol.Count > 0) 
     { 
      DataTable data = blockingCol.Take(); 
      index.UpdateIndex(GetLuceneDocs(data)); 
     } 
    } 


public static void Main(System.String[] args) 
{ 
      index = new LuceneIndex(); 
      blockingCol = new BlockingCollection<DataTable>(2); 
      // Create the producer and consumer tasks. 
      Task Prod = new Task(Producer); 
      Task Con = new Task(Consumer); 
      // Start the tasks. 
      Con.Start(); 
      Prod.Start(); 
      // Wait for both to finish. 
      try 
      { 
       Task.WaitAll(Con, Prod); 
      } 
      catch (AggregateException exc) 
      { 
       Console.WriteLine(exc); 
      } 
      finally 
      { 
       Con.Dispose(); 
       Prod.Dispose(); 
       blockingCol.Dispose(); 
      } 
} 

拒絕這種懸掛的任何人證實?有什麼解決辦法嗎?

回答

8

是的,我可以證實這一點。你不在.NET 4.5上,是嗎?它應該在那裏修復(並且您的評論在這個答案似乎證實了這一點)。

無論如何,寫下你自己的一個包裝DataTable,當你完成了表格清理包裝。這使得它符合GC的條件。包裝不會很早開始,但很小。

class Wrapper<T> { public T Item; } 
+0

我在.net 4.5上。我實際上使用亞音速收集而不是數據表。爲了簡單起見,我在這個例子中只包含了數據表。我會嘗試你的解決方案。 – NSjonas

+0

我想這是不固定的然後(可能我記得)。不過,我自己也看到了這個問題。 – usr

+1

包裝 wrapper = BlockingCol.Take(); //做東西 wrapper.Item = null;這是你的意思嗎? – NSjonas