2012-10-10 10 views
6

Używam Producer/Consumer Pattern z System.Collection.Concurrent.BlockingCollection<DataTable> do pobierania danych z bazy danych (producenta) i tworzenia indeksu Lucene na danych (konsumenta).. Blokowanie jednoczesne .Net ma wyciek pamięci?

Producent przechwytuje 10000 rekordów jednocześnie i dodaje zestaw do BlockingCollection<DataTable>. Konsument (który jest nieco wolniejszy) następnie chwyta te 10000 i tworzy indeks.

Kolekcja blokująca jest ograniczona do 5 <DataTable> z 10 000 wierszy.

Początkowo program działał świetnie, ale po jego pobraniu około 150000 wierszy zauważyłem, że pamięć moich komputerów jest wyczerpana i spowalnia indeksowanie.

Wygląda na to, że BlockingCollection po ustawieniu elementu nie ustawi podstawowej szczeliny macierzy na null.

Kod:

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(); 
      } 
} 

Czy ktoś może potwierdzić z odrzucić tę zawieszenie? Czy jest jakaś praca?

Odpowiedz

8

Tak, mogę to potwierdzić. Nie jesteś na .NET 4.5, prawda? To ma być tam naprawione (i twoje komentarze pod tą odpowiedzią zdają się to potwierdzać).

W każdym razie, napisz sobie wrapper wokół DataTable i wyczyść to opakowanie, gdy skończysz z tabelą. To sprawia, że ​​kwalifikuje się do GC. Opakowanie nie będzie wcześnie GC, ale jest małe.

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

Jestem na .net 4.5. W rzeczywistości używam kolekcji poddźwiękowej zamiast datatable. Po prostu włączyłem datatables w tym przykładzie dla uproszczenia. Wypróbuję twoje rozwiązanie. – NSjonas

+0

Myślę, że to nie jest naprawione (prawdopodobnie zapamiętałem). Sam widziałem ten problem. – usr

+1

Wrapper wrapper = BlockingCol.Take(); // do rzeczy wrapper.Item = null; To masz na myśli, prawda? – NSjonas