Ver Mensaje Individual
  #1 (permalink)  
Antiguo 07/02/2018, 02:13
ugeltroglodita
 
Fecha de Ingreso: diciembre-2012
Mensajes: 17
Antigüedad: 11 años, 4 meses
Puntos: 2
Pérdida de memoria en aplicación multihilo

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
Código:
PerformanceCounter ramCounter = new PerformanceCounter("Memory", "Available MBytes");"
y en cada pasada del thread lo ejecuto mediante
Código:
"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:
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:
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
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);
}