2012-10-10 45 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