Lectura y escritura en el puerto serie llena la memoria RAM
-
Hola a todos, estoy trabajando en un programa muy simple y sencillo. No tiene mucho misterio.
Creo tantos hilos como puertos serie vaya a usar para leer varias redes MODBUS. En cada hilo, un puerto serie. Al inicio de cada hilo, creo las sentencias MODBUS que necesitaré para leer toda la red de dispositivos MODBUS que estén conectados a esa red. Después en un bucle infinito donde:
- envio una sentencia,
- espero a la respuesta,
- proceso la respuesta,
- almaceno el resultado
- y paso a la siguiente sentencia MODBUS.
Al final de cada iteracción del bucle, cuando ya he leido todas las sentencias. Mediante señales y slots envío los resultados a otro objeto que hace la función de servidor TCP y enviará los datos en formato json cuando otra apliación le consulte.
El programa funciona bien hasta que llega un punto en el que sin previo aviso, se rompe. Salta un mensaje de Windows y el programa se cierra.
Problema: Tras investigar y pasar horas buscando, me he dado cuenta que el consumo de la memoria RAM va aumentando poco a poco. Más rápido cuantas más redes y dispositivos MODBUS intente leer. Buscando qué variable consumia más y más RAM me he dado cuenta del consumo de memoria aumenta tras cada escritura y lectura del puerto serie. en las sentencias:
portSerial->write(myQByteArrayData);
y aquí:
mybuffer = portSerial->readAll();
He investigado en la documentación oficial y veo que hay que emplear
bool QSerialPort::clear(Directions directions = AllDirections)
.Cuando intento usarlo, el programa empieza a funcionar mal, me da errores en lecturas MODBUS que antes no tenía, el puerto serie me devuelve el error con código 10
QSerialPort::UnsupportedOperationError
lo que significa "The requested device operation is not supported or prohibited by the running operating system." Vamos que Windows no soporta esa acción. No especifica qué "operación" es la que no soporta, pero la única nueva esQSerialPort::clear()
.Pregunta: ¿Como soluciono el aumento del consumo de memoria RAM?
-
He encontrado la solución en parte. Me explico: ya no se me muere!!
En un "try" cuando se daba cierta condición que nunca se debería producir, lanzaba un throw de tipo QString y en el "catch" solo recogia las excepciones que se producían por excepciones.
Ahora ya no se me muere el programa nunca. Pero el problema del consumo de memoria continua. El funcionamiento del programa es correcto y actua tal como se espera. Pero cuando se echa un vistazo al consumo de memoria se ve que el consumo de RAM va aumentando poco a poco sin parar.
Estoy repasando todo, pero sigo sin encontrar el error. ¿A nadie le ha pasado? ¿Alguna idea de por donde mirar o como hacer para encontrar el fallo?
Un saludo a todos.
-
Sigo sin poder solucionarlo. ¿Nadie tiene ni una sugerencia?
-
Hola,
Creas objectos a memoria con un "new" en alguna parte?
Cuando dices que "almaceno el resultado" a que te refieres? Los vas acumulando?Podrias postear algo de código para que podamos ayudarte.
Recuerdo haber utilizado las librerias "Visual Leak Detector" (https://vld.codeplex.com/) para detectar si hay memoria sin eliminar cuando termina la aplicación.
Un saludo,
-
He revisado el código y los objetos que creo dinámicamente se crean solo al inicio. Dependiendo del número de puertos serie que tenga conectados se crean tantos objetos, y cada uno se ejecuta en un hilo diferente.
En teoría el programa nunca debería terminar, debería funcionar indefinidamente. Esta hecho para recoger datos de instrumentos industriales mediante el protocolo MODBUS. De todas maneras, está preparado para que cuando se cierre se eliminen los objetos creados de forma dinámica.
Cuando digo "almacenar el resultado" me refiero a que tras la lectura de cada instrumento voy guarndando en un QStringList los datos. Tras la lectura de toda la red de instrumentos MODBUS, proceso este QStringList y guardo la información en un JSON temporal. Cuando termino de procesarlo, lo copio en un JSON "final". Machacando la información que había previamente en este JSON "final". Luego limpio el QStringList y el JSON "temporal" para almacenar los datos de las nuevas lecturas.
Lo hago de esta manera para que en cualquier momento en el que reciba una petición del programa externo tenga un JSON "final" con toda la información disponible. En cada iteracción del bucle infinito, cuando tengo todos los datos, en el formato correcto y validado, actualizo el contenido. No le añado nada al final. Borro lo antiguo y añado lo nuevo.
He revisado varias veces estas variables, pensaba que en alguna de ellas acumularía datos sin borrar el contenido previo, pero no. Se limpian correctamente y siempre mantienen el tamaño esperado cuando las reviso en modo debug. Sin embargo, en el monitor del SO sigue mostrándome que el proceso del programa va aumentando poco a poco su consumo de memoria RAM.
Te copiaría el código fuente, pero es bastante largo y no se qué parte del programa copiarte, no se qué sección es el que falla.
-
Hola,
Has probado las librerias VLD para detectar Memory Leaks?
Que versión de Qt utilizas? No habrá un BUG en la clase QSerialPort?
Prueba a eliminar la parte donde procesas el QStringList y lo pasas a un JSON. Cuando tengas la lectura de toda la red Modbus pon un punto de depuración y asegurate que borras el QStringList. Si tienes el QStringList declarado en una clase puedes poner un punto de depuración en el destructor de la clase y mirar la longitud al cerrar la aplicación(tarda mucho en cerrar la aplicación?).
No se me ocurren mas cosas a probar...