java - example - Tomcat se está quedando sin memoria gradualmente con las aplicaciones WebSocket implementadas
java websockets eclipse (3)
Como todos sabemos, Java GC es perezoso. Su memoria seguirá creciendo hasta que no pueda tener más memoria, luego se activará un GC para recolectar basura.
En la captura de pantalla de su VisualVM, podemos ver que el uso de la memoria es relativamente normal: más memoria se usa con el tiempo, el uso de la memoria se redujo después de GC.
Así que me pregunto si tu aplicación realmente se bloqueará porque OOM. Puede probarlo en su entorno de prueba y hacer que se analice el volcado JVM de OOM, que es más útil.
Por cierto, sugiero VisualVM a través de MAT, porque MAT incluirá algunos objetos unreachable como raíz GC. Hará que el análisis de la memoria sea muy ineficiente y dará un resultado diferente al de otras herramientas, que conocí en uno de nuestros proyectos.
Tengo Tomcat 8.5.9 ejecutándose en una caja de AWS con 10 aplicaciones WebSocket diferentes implementadas que básicamente actúan como intermediarios de mensajes. El conector https está utilizando el Http11NioProtocol. El único parámetro que he establecido es maxThreads = 200 junto con la información del certificado.
El volumen de solicitud no es muy alto. Funciona desde el lunes por la mañana, y esto es lo que dice el estado del gerente:
Hilos máximos: 200
Número de hilos en curso: 38
Hilo actual ocupado: 0
Mantener los sockets vivos cuentan: 1
Tiempo máximo de procesamiento: 234 ms
Tiempo de procesamiento: 17.254 s
Recuento de solicitudes: 33351
Recuento de errores: 325
Bytes recibidos: 0.00 MB
Bytes enviados: 34.07 MB
Después de unos días, me doy cuenta de que el uso de la memoria sigue creciendo. Tengo que reiniciar los servicios de Tomcat cada dos semanas aproximadamente para evitar la obtención de una excepción OutOfMemoryException.
He estado tomando volcados de pila y analizando con el Eclipse MAT, que siempre apunta a la clase WsFrameServer como el sospechoso del problema. El volcado más reciente muestra lo siguiente:
5,146 instancias de "org.apache.tomcat.websocket.server.WsFrameServer",
cargados por "java.net.URLClassLoader @ 0x6c0047c28" ocupan 1,383,143,200
(73.13%) bytes. Estas instancias están referenciadas desde una instancia de
"java.util.concurrent.ConcurrentHashMap $ Node []"
El Dominator Tree tiene actualmente 106,000 entradas, la mayoría de las cuales son de la clase WsFrameServer.
¿Estoy haciendo algo mal o es esto "normal"? ¿Hay alguna configuración específica en Tomcat o en el Conector que debo configurar para evitar que esto suceda?
Gracias por adelantado.
EDIT: No estoy seguro de si esto es útil, pero aquí es cómo se ve el monitor de VisualVM:
Falta el código de tu pregunta. (especialmente cómo gestionas la conexión websocket)
¿Usaste Tomcat en modo asíncrono con una lista de conexiones en algún lugar?
¿No te olvidas de enlazar el evento de cierre Y error a un código que elimina la conexión defectuosa de la lista?
Es difícil estar seguro sin más detalles, pero esto probablemente esté relacionado con la retención de la sesión. Lo que creo que está sucediendo es que el WsFrameServer
que se extiende a WsFrameBase
se agrega a la sesión.
Si tiene una política de retención de sesión ilimitada, finalmente se quedará sin memoria.
Intenta establecer una sessionTimeout
no- sessionTimeout