C# sockets, hilos y memoria.

SeiYa

Buenas, a ver, tengo unos problemillas.

Estoy desarrollando una clase en C# que sirve a modo de servidor TCP asíncrono utilizando sockets e hilos.

Tengo en un par de listas los sockets abiertos y los hilos.

Cada vez que se desconecta un cliente su socket se cierra y se elimina de la lista, quedando en el "limbo", con los hilos pasa lo mismo, examino los hilos y elimino los de los clientes fantasma o del cliente recien desconectado. Después mando al recolector de basura que limpie por si las moscas. El caso es que con esta clase TCP he hecho un servidor de prueba que acepta conexiones y demás y lo testeo por telnet (hyperterminal) pero pasa que no hace más que aumentar la memoria cuando se conectan clientes (obvio) pero es que cuando se desconectan si baja son solo 10kb o ni si quiera baja o incluso aumenta 400 kb más la memoria.

No sé porqué, elimino hilos y sockets y finalmente tengo constancia de que existen únicamente activos los sockets e hilos de los clientes conectados en ese momento.

Por eso no sé que puede pasar o como liberar memoria porque es el principal problema que tiene la clase.

Un saludo y gracias ;)

Soltrac

Se q no tiene na q ver..pero pq no usas .NET remoting en vez de sockets y te quitas de la programación a bajo nivel?

He hecho conexiones con .NET remoting de muchísimos usuarios a la vez, sin tener q preocuparme de comunicación asíncrona, ni hilos ni nada y la memoria va perfecta, ni 1 leak.

SeiYa

El caso es que la clase esta es para un servidor que recibe imágenes de distintas cámaras en distintas partes que únicamente envían datos binarios por un socket.

Las cámaras son así y no me quedan más cojones XD

Pero gracias por lo de Remoting, le echaré un vistazo por conocerlo, no lo sabía.

Soltrac

#3 Entonces copia el código del destructor, pa q veamos si eliminas todo bien de memoria, aunque si copiaras la clase entera sería mejor :)

SeiYa

Toma la clase XD

Hay muchas cosas que podrían cambiarse pero únicamente me molesta el que cuando se desconecta un cliente (no el destructor de la clase) no se libera la memoria que "él" ha aumentado y utilizado.

EDIT: mejor en pastebin

http://pastebin.com/m68dc287c

Soltrac

Veamos...

Prueba a cambiar el orden de

this.intIDs.RemoveAt(this.skClientes.IndexOf(skCliente));
this._skClientes.Remove(skCliente);
skCliente.Disconnect(false);
skCliente.Close();

por

skCliente.Disconnect(false);
skCliente.Close();
this.intIDs.RemoveAt(this.skClientes.IndexOf(skCliente));
this._skClientes.Remove(skCliente);

Mira tb si puedes llamar a skCliente.Dispose() <- No se si tendrá el método.

Luego prueba lo siguiente:

En vez de llamar a .Interrupt() prueba con .Abort() en el hilo.

y por último prueba tb:

this._thClientes = nuevaLista;

por

this.thClientes.Clear();
this.
thClientes = nuevaLista;

No se, prueba todo, aunque yo apuesto q el leak está en dentro de este for:

foreach (Thread hilo in this._thClientes)

SeiYa

Bueno, no tenia dispose XD pero nada, sigue igual incluso quitando el foreach sigue muy similar (igual un poco menos).

El caso es que cada vez que envio 1 dígito por telnet, sube la memoria.

Tengo siempre un numero activo de hilos igual a los clientes conectados + 1 (1 para el servidor y luego 1 para cada cliente).

Osea si tengo 1 cliente tengo 2 hilos activos siempre, pero por cada byte que entra sube la memoria y joder, luego nunca baja y si estoy recibiendo imágenes de una cámara cada 30 segundos me puedo morir XD

Me trae de cabeza esta parte de la memoria, eso sí, /// sumarys no me faltan XD

Soltrac

Prueba a meter el NetworkStream del recibe datos dentro de un using

algo así:

using (NetworkStream DatosAceptados = new NetworkStream(ClienteActual))
{
}

SeiYa

Joder nada, pero coño, ya no pido que me devuelva la memoria consumida, ya solo pido que por lo menos no consuma más memoria al liberar un puto hijo joder !! Es que se desconecta un usuario y elimina sockets, hilos todo ... pero suma memoria, porqué!!!!!!!!

Soltrac

#9 Ponte a comentar zonas del código y a ver si localizas donde se va la memoria. De todas formas, el recolector de basura actua cuando le sale del nabo, has probado a dejarlo un buen rato encendido pa ver si deja de crecer en algún momento?

SeiYa

Voy a probar a tomarme un pincho de tortilla y un bocata a ver que pasa y ya luego si eso me lo tomo con más calma XD

Puni

No he programado en C# pero si se algo es q confiar en los destructores para liberar recursos es una politica bastante mala partiendo de la base de que no sabes cuando se van a ejecutar o siquiera si lo van a hacer. No se ahora mismo cual seria una buena solucion (a parte de llamar al GC a mano q es un poco solucion gocha xD), pero intentaria liberarlos de forma manual en otro metodo y luego dejarlos en "estado zombi" hasta q el recolector los acabe de liberar.

SeiYa

Rehice la clase totalmente.

Ya no uso yo los hilos sino que uso los métodos asíncronos de los sockets:

http://wallack.pastebin.com/m6bfd73df

Cuando me conecto con 100 clientes obviamente sube la memoria. Al desconectarse no baja. Al desconectar el servidor si baja.

¿Cómo podría liberar la memoria del servidor? ya falta poco XD

Soltrac

Por curiosidad...

Conectas 100 clientes (sube la memoria p ej pon q gasta 100 de memoria para pensar en nº abstractos)

Desconectas los 100 clientes

¿Cúando conectas otros 100 clientes sube la memoria a 200, es decir, el gasto de memoria se duplica?

¿Y si haces lo mismo se triplica?

Es q...la desconexión no tiene leaks, está bien hecha lo único q se me ocurre es q llames a cliente.Socket.Close() y cliente.Socket.Dispose() :S

SeiYa

No tengo disposeeeeeeeeeee es de 2003!! desapareció en 2005 XD voy a probar.

EDIT:

Conecto 100 clientes, les desconecto, conecto 100 y sube más la memoria, desconecto, conecto 100 y sube más la memoria.

Para bajarla, desconecto el servidor, le conecto y vuelvo a desconectar y ya baja.

Lo que creo que ocurre es que el servidor sigue con los hilos por detrás, no lo entiendo XD

Soltrac

#15 Q hablas loco ... si yo uso 2008 y dispose sigue existiendo xDDD, otra cosa es q los sockets no lo tengan, pero si tu dices q es tema del servidor..entonces eso no tiene nada q ver :S

Bueno..voy comentandote.

Yo utilizaba una clase de ayuda de codeproject q estaba bastante currada:

http://www.codeproject.com/KB/IP/AsyncSocketServerandClien.aspx

Mira esos ejemplos y modificalos a ver si tienen memory leaks

Aquí tb tienes un chat http://www.codeproject.com/KB/IP/ChatAsynchTCPSockets.aspx Modificalo un poco para ver si haciendo muxas conexiones q ocurre.

Yo he trabajado con sockets y nunca he tenido problemas de leaks. Además veo tu código y no veo nada raro en principio. No se, seguiré mirándolo pero deberías comprobar otros códigos como los q te he copypasteado para ver si a ellos les pasa lo mismo.

Ya contarás q tal.

Deathtime

Sacado del MSDN:

http://msdn.microsoft.com/es-es/library/7a2f3ay4(VS.80).aspx

workerObject.RequestStop();

También es posible terminar un subproceso desde otro con una llamada a Abort, pero esto termina a la fuerza el subproceso afectado sin comprobar si ha completado su tarea y no proporciona ninguna oportunidad para la slimpieza de recursos. Es preferible la técnica motrada en este ejemplo.

Usuarios habituales

  • Deathtime
  • Soltrac
  • SeiYa
  • Puni