haskell memory-leaks profiling ghc

haskell - Depuración de una pérdida de memoria que no se muestra en el perfil de montón



memory-leaks profiling (1)

Estoy trabajando en un daemon Haskell que recibe y procesa solicitudes JSON. Si bien las operaciones del daemon son complejas, la estructura principal se mantiene intencionalmente simple: su estado interno es solo un IORef con una estructura de datos y todos los hilos realizan operaciones atómicas en este IORef . Luego hay algunos hilos que sobre un disparador toman el valor de hacer algo con él.

El problema es que el daemon está perdiendo memoria y no puedo descubrir por qué. Ciertamente está relacionado con las solicitudes: cuando el daemon recibe varias solicitudes por segundo, pierde algo así como 1 MB / s (según lo informado por las herramientas de Linux). El consumo de memoria aumenta constantemente. Sin solicitudes, el consumo de memoria permanece constante.

Lo que me desconcierta es que nada de esto se muestra en los perfiles de GHC. O me falta algo en los parámetros de creación de perfiles, o la memoria es consumida por otra cosa:

Ejecutar con +RTS -hc -xt -p :

Ejecutar con +RTS -hr -xt -p :

Durante esta ejecución de prueba, el daemon consume más de 1 GB. Por lo tanto, los datos de generación de perfiles claramente no se corresponden con la memoria consumida real en órdenes de magnitud. (Entiendo que el RTS, el GC y el perfilado se agregan al consumo de memoria real, pero esta diferencia es demasiado grande y no corresponde al consumo cada vez mayor).

Ya traté de rnf todos los datos de estado del daemon dentro del IORef , así como las solicitudes JSON analizadas (para evitar que se retuvieran partes de las cadenas JSON), pero sin mucho éxito.

Cualquier idea o sugerencia bienvenida.

Actualización: el daemon se ejecuta sin -threaded , por lo que no hay subprocesos de nivel del sistema operativo.

Las estadísticas de GC están mucho más cerca del perfil de montón que de las cifras reportadas por Linux:

Alloc Copied Live GC GC TOT TOT Page Flts bytes bytes bytes user elap user elap [...] 5476616 44504 2505736 0.00 0.00 23.21 410.03 0 0 (Gen: 0) 35499296 41624 2603032 0.00 0.00 23.26 410.25 0 0 (Gen: 0) 51841800 46848 2701592 0.00 0.00 23.32 410.49 0 0 (Gen: 0) 31259144 36416 2612088 0.00 0.00 23.40 410.61 0 0 (Gen: 0) 53433632 51976 2742664 0.00 0.00 23.49 412.05 0 0 (Gen: 0) 48142768 50928 2784744 0.00 0.00 23.54 412.49 0 0 (Gen: 0) [...]

Actualización 2: Encontré el origen del problema, la pérdida de memoria es causada por handleToFd (consulte este problema para la biblioteca de Unix ). Me pregunto cómo sería posible identificar de manera más efectiva una fuga de este tipo (tal vez en una pieza de código extranjera).


Si bien no estoy familiarizado con el daemon Haskell en sí mismo, respondiendo a su pregunta "¿cómo sería posible identificar con mayor eficacia una fuga de este tipo?", Podría ser posible utilizar

valgrind --leak-check=yes haskelldaemon (mejor si lo compila con información de depuración),

O, si la fuga ocurre en la biblioteca compartida, pruebe

LD_PRELOAD="yourlibrary.so" valgrind your-executable .