2010-02-25 9 views
14

Tenemos un componente de servidor escrito en .Net 3.5. Se ejecuta como servicio en Windows Server 2008 Standard Edition. Funciona muy bien, pero después de algún tiempo (días) notamos desaceleraciones masivas y un conjunto de trabajo aumentado. Esperábamos algún tipo de pérdida de memoria y usamos WinDBG/SOS para analizar volcados del proceso. Desafortunadamente, el GC Heap no muestra ninguna fuga, pero notamos que el montón del código JIT ha crecido de 8 MB después del inicio a más de 1 GB después de unos días..NET JIT Code Cache leakking?

No utilizamos ninguna técnica de generación de código dinámico por nuestra cuenta. Usamos Linq2SQL que es conocido por la generación de código dinámico, pero no sabemos si puede causar tal problema.

La pregunta principal es si hay alguna técnica para analizar el volcado y comprobar de dónde vienen todos estos bloques de Heap de Host Code que se muestran en los volcados de WinDBG.

[Actualización]

Por el momento nos hizo un poco más de análisis y tenía Linq2SQL como probable sospechoso, sobre todo porque no usamos consultas precompilados. El siguiente programa de ejemplo crea exactamente el mismo comportamiento donde más y más bloques de Heap de Host Code se crean a lo largo del tiempo.

using System; 
using System.Linq; 
using System.Threading; 

namespace LinqStressTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      for (int i = 0; i < 100; ++ i) 
       ThreadPool.QueueUserWorkItem(Worker); 
      while(runs < 1000000)    
      { 
       Thread.Sleep(5000); 
      } 
     } 

     static void Worker(object state) 
     { 
      for (int i = 0; i < 50; ++i) 
      { 
       using (var ctx = new DataClasses1DataContext()) 
       { 
        long id = rnd.Next(); 
        var x = ctx.AccountNucleusInfos.Where(an => an.Account.SimPlayers.First().Id == id).SingleOrDefault(); 
       } 
      } 
      var localruns = Interlocked.Add(ref runs, 1); 
      System.Console.WriteLine("Action: " + localruns); 
      ThreadPool.QueueUserWorkItem(Worker); 
     } 

     static Random rnd = new Random(); 
     static long runs = 0; 
    } 
} 

Cuando reemplazamos la consulta Linq por una precompilada, el problema parece desaparecer.

+0

@pitchfork - un poco al azar. ¿Intentó desactivar el seguimiento de cambios en 'DataContext'? 'ctx.ObjectTrackingEnabled = false' como la primera línea dentro de la instrucción using? –

Respuesta

0

La única forma que conozco de fugas de memoria en .NET se debe a la gestión de eventos, mira esto:

  1. link1
  2. también, echar un vistazo a la siguiente pregunta: How do I avoid a memory leak with LINQ-To-SQL?
  3. también , eche un vistazo a ANTS profiler
  4. Y, ha considerado, que tal vez, en algún momento, tendrá muchos hilos en ejecución? que naturalmente consumirá mucha memoria?
+0

Gracias por los consejos. Usando WinDBG pudimos demostrar que no goteamos memoria en el montón administrado, también siempre eliminamos nuestro DataContext después de que la unidad de trabajo está lista. – user173674

1

Use un 'singleton' DataContext, en lugar de volver a crearlo todo el tiempo en el ciclo.

Estoy seguro de que el efecto será el mismo que el de las consultas compiladas.

Actualización:

Este problema está destinado a ser 'rectificado' en .NET 4, ya que soporta conjuntos dinámicos GC'able.