2012-10-10 25 views
6

Estoy usando un Producer/Consumer Pattern con un System.Collection.Concurrent.BlockingCollection<DataTable> para recuperar datos de una base de datos (productor) y crear un índice Lucene en los datos (consumidor)..Net Concurrent BlockingCollection tiene una pérdida de memoria?

El productor toma 10000 registros a la vez y agrega el conjunto al BlockingCollection<DataTable>. El consumidor (que es un poco más lento) luego toma esos 10000 y crea un índice.

La colección de bloqueo está limitada a 5 <DataTable> de 10000 filas cada una.

Al principio, el programa funciona bien, pero después de recibir aproximadamente 150000 filas, noté que la memoria de mi computadora está al máximo y se ralentiza.

Parece que BlockingCollection no establece la ranura de la matriz subyacente en null después de que se toma el elemento.

Código:

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(); 
      } 
} 
¿Puede alguien confirmar

de rechazar esta suspensión? Y hay algo de trabajo?

Respuesta

8

Sí, puedo confirmar esto. No estás en .NET 4.5, ¿verdad? Se supone que debe estar arreglado allí (y sus comentarios en esta respuesta parecen confirmar esto).

De todos modos, escriba usted mismo un contenedor alrededor de un DataTable y borre ese contenedor cuando haya terminado con la tabla. Eso lo hace elegible para GC. El envoltorio no se cargará temprano en GC, pero es muy pequeño.

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

Estoy en .net 4.5. De hecho, estoy usando una colección subsónica en lugar de datatable. Acabo de incluir tablas de datos en este ejemplo por simplicidad. Voy a probar tu solución también. – NSjonas

+0

Supongo que no es fijo entonces (probablemente lo recordé). Aunque he visto este problema yo mismo. – usr

+1

Wrapper wrapper = BlockingCol.Take(); // hacer las cosas wrapper.Item = null; Esto es lo que quieres decir, ¿verdad? – NSjonas

Cuestiones relacionadas