我正在处理接收和处理JSON请求的Haskell守护程序。虽然守护进程的操作很复杂,但主要结构有意保持简单:它的内部状态只是一个带有数据结构的IORef
,并且所有线程都对此IORef
执行原子操作。然后有一些线程在触发器上取值时用它做一些事情。
问题是该守护进程泄漏了内存,我无法找到原因。它肯定与请求相关:当守护进程每秒收到多个请求时,它会泄漏大小为1MB / s(如Linux工具所报告的那样)。内存消耗稳步增长。没有请求,内存消耗保持不变。
令我感到困惑的是,这些都没有在GHC分析中显示出来。要么我在配置文件参数中缺少某些内容,要么内存被其他内容消耗:
使用+RTS -hc -xt -p
:
使用+RTS -hr -xt -p
:
在此测试运行期间,守护程序随后消耗超过1GB。因此,分析数据显然不会与实际消耗的内存相对应的数量级。 (我知道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 库,请参阅this issue )。我只是想知道如何能够更有效地查明这种泄漏(可能发生在外国代码中)。
答案 0 :(得分:2)
虽然我不熟悉Haskell守护程序本身,回答你的问题"如何更有效地查明这样的漏洞",有可能使用
valgrind --leak-check=yes haskelldaemon
(如果使用调试信息编译它会更好),
或者,如果泄漏发生在共享库中,请尝试
LD_PRELOAD="yourlibrary.so" valgrind your-executable
。