Подтвердить что ты не робот

Отладка утечки памяти, которая не отображается при профилировании кучи

Я работаю над демоном Haskell, который получает и обрабатывает запросы JSON. В то время как операции демона сложны, основная структура намеренно остается простой: ее внутреннее состояние - это просто IORef с структурой данных, и все потоки выполняют атомарные операции над этим IORef. Затем есть несколько потоков, которые на триггере принимают значение a что-то с ним.

Проблема заключается в том, что демона утечка памяти, и я не могу понять, почему. Это, безусловно, связано с запросами: когда демон получает несколько запросов в секунду, он течет примерно как 1 МБ/с (как сообщается инструментами Linux). Потребление памяти неуклонно увеличивается. Без запросов потребление памяти остается постоянным.

Что меня озадачивает, что ничто из этого не показывает в профилировании GHC. Либо я пропускаю что-то в параметрах профилирования, либо память потребляется чем-то другим:

Выполнить с +RTS -hc -xt -p:

screenshot of profiler output

Запустите с помощью +RTS -hr -xt -p:

screenshot of profiler output

Во время этого пробного запуска демона впоследствии потребляет более 1 ГБ. Таким образом, данные профилирования явно не соответствуют фактической потребляемой памяти на порядки. (Я понимаю, что RTS, GC и профилирование сами по себе добавляют к реальному потреблению памяти, но эта разница слишком велика и не соответствует постоянно растущему потреблению.)

Я уже пробовал rnf все данные состояния демона внутри IORef, а также разобранные JSON-запросы (чтобы избежать частичных JSON-строк), но без особого успеха.

Любые идеи или предложения приветствуются.

Обновление: Демон работает без -threaded, поэтому нет потоков уровня ОС.

Статистика GC намного ближе к профилированию кучи, чем к числам, указанным в 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)
[...]

Обновление 2: я нашел причину проблемы, утечка памяти вызвана handleToFd (см. эту проблему для библиотека unix). Мне просто интересно, как можно было бы более точно определить такую ​​утечку (возможно, в чужом фрагменте кода).

4b9b3361

Ответ 1

Пока я не знаком с самим демоном Haskell, отвечая на ваш вопрос "как можно было бы более точно определить такую ​​утечку", можно было бы использовать

valgrind --leak-check=yes haskelldaemon (лучше, если вы скомпилируете его с информацией об отладке),

ИЛИ, если утечка происходит в общей библиотеке, попробуйте

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