[ Foro de C# ]

Pérdida de memoria en aplicación multihilo

07-Feb-2018 09:20
Invitado (Eugenio)
0 Respuestas

El escenario es el siguiente: una aplicación con varios hilos: 2 para pedir datos a diferentes fuentes, 3 para actualizar diferentes informaciones en pantalla, y 1 para reproducir audios a demanda.
El problema: la aplicación tiene que funcionar non-stop, y al arrancar funciona bien, pero al cabo de un tiempo (no siempre el mismo, suelen ser entre 5 y 8 horas) acaba fallando. La traza de error apunta a uno de los hilos de pintado, en donde me salta la excepción "System.OutOfMemoryException" durante 5 o 6 minutos, hasta que al final el programa se para. Ese thread ejecuta dentro otros dos, que son 2 animaciones (fadeIn,fadeOut) que duran 1seg, antes y después de actualizar la información. Si quito esas animaciones el programa no falla (almenos durante 24h). Me gustaría mantener las animaciones, y que memoria
ayudarais a detectar qué estoy haciendo mal, supongo que no estoy liberando recursos o algo parecido.

Por mi parte he mirado dos cosas:
1) Memoria de la aplicación: he creado esta variable
PerformanceCounter ramCounter = new PerformanceCounter("Memory", "Available MBytes");"
y en cada pasada del thread lo ejecuto mediante
"RAM disponible: " + ramCounter.NextValue() + "MB"
El valor está siempre en torno a 3.5/4Gb, así que no parece estar perdiendo memoria.
2) Número de threads: leí que hay un límite de threads que una aplicación puede crear, y pensé que si no los estaba cerrando adecuadamente quizá ese fuera el problema. Pero no parece tampoco. Ejecuto esto en cada pasada  y me da siempre un valor estable de entre 30 y 35:
"NumThreads: "+System.Diagnostics.Process.GetCurrentProcess().Threads.Count"


Adjunto el código, y a ver si me podéis decir qué estoy haciendo mal:

Thread que pinta información (si quito las 3 líneas de cada animación; la aplicación funciona ok):

while (true){
   try{
       EscribirLogError("PintarTiempos - RAM disponible: " + ramCounter.NextValue() + "MB",false);
       tiempoPrevisiones = int.Parse(ConfigurationManager.AppSettings["TIEMPOPREVS"]);

//Animación quitar tiempos
tFadeOut = new Thread(new ThreadStart(FadeOut));
tFadeOut.SetApartmentState(ApartmentState.STA);
tFadeOut.Start();
//Pintar tiempos
this.window.pintaTiempos(previsiones);
Console.WriteLine("NumThreads: " + System.Diagnostics.Process.GetCurrentProcess().Threads.Count);
EscribirLogError("NumThreads: "+System.Diagnostics.Process.GetCurrentProcess().Threads.Count,false);
//Animación tiempos nuevos
tFadeIn = new Thread(new ThreadStart(FadeIn));
tFadeIn.SetApartmentState(ApartmentState.STA);
tFadeIn.Start();
                       
Thread.Sleep(tiempoPrevisiones * 1000);
                   
   }catch(Exception e){
       EscribirLogError("PintaTiempos:" + e.Message, true);
}
}

public void FadeIn()
       {
           TimeSpan fadeInTime = TimeSpan.Parse("00:00:01");
           Double opacityFinalFadeIn = 1d;
           Thread.Sleep(750);
           this.window.FadeIn(fadeInTime, opacityFinalFadeIn);
       }

La función fadeIn de la instancia this.window
public void FadeIn(TimeSpan fadeInTime, Double d)
{
this.Dispatcher.Invoke(new System.Action(() =>
{
try
{
var fadeInAnimation = new DoubleAnimation(1d, fadeInTime);
for (int i = 0; i < this.lblTiempos.Length; i++)
{
this.lblLineas[i].BeginAnimation(Label.OpacityProperty, fadeInAnimation);
this.lblDestinos[i].BeginAnimation(Label.OpacityProperty, fadeInAnimation);
this.lblTiempos[i].BeginAnimation(Label.OpacityProperty, fadeInAnimation);
}
}
catch (Exception e)
{
this.programa.EscribirLogError("FadeIn.Dispatcher:" + e.Message, true);
}
}), null);
}




Si ya eres usuario del sistema, puedes contestar desde tu cuenta y así ganar prestigio.

Si sólo eres un visitante, puedes optar por...