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
Código:
y en cada pasada del thread lo ejecuto mediante PerformanceCounter ramCounter = new PerformanceCounter("Memory", "Available MBytes");"
Código:
El valor está siempre en torno a 3.5/4Gb, así que no parece estar perdiendo memoria."RAM disponible: " + ramCounter.NextValue() + "MB"
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:
Código:
"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 líneas de las animaciones; la aplicación funciona ok)
Código:
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); } }
Código:
La función fadeIn de la instancia this.windowpublic void FadeIn() { TimeSpan fadeInTime = TimeSpan.Parse("00:00:01"); Double opacityFinalFadeIn = 1d; Thread.Sleep(750); this.window.FadeIn(fadeInTime, opacityFinalFadeIn); }
Código:
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); }