使用Valgrind排查段错误时memcheck-amd64-遭OOM终止求助
问题场景
我用Valgrind排查代码段错误时,程序运行到触发错误的位置就终止了。查看/var/log/syslog发现Valgrind的memcheck-amd64-进程被OOM Killer杀死,日志如下:
Sep 7 12:48:34 fabiano-HP kernel: [10154.654505] oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/user.slice/user-1000.slice/session-c2.scope,task=memcheck-amd64-,pid=3688,uid=1000
Sep 7 12:48:34 fabiano-HP kernel: [10154.654560] Out of memory: Killed process 3688 (memcheck-amd64-) total-vm:11539708kB, anon-rss:6503332kB, file-rss:0kB, shmem-rss:0kB, UID:1000 pgtables:12952kB oom_score_adj:0
Sep 7 12:46:26 fabiano-HP org.freedesktop.thumbnails.Cache1[3661]: message repeated 3 times: [ libpng error: Read Error]
Sep 7 12:48:34 fabiano-HP systemd[1]: session-c2.scope: A process of this unit has been killed by the OOM killer.
使用的Valgrind启动命令:
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --log-file=valgrind-out.txt ./mainCPU -ellpack
当前Valgrind未生成指定的valgrind-out.txt,无法定位问题根源,以下是解决办法:
一、解决OOM问题,避免Valgrind被杀死
Valgrind的memcheck工具会让内存占用飙升(通常是原程序的10-20倍),优先从内存优化入手:
精简Valgrind检查选项
- 关闭高内存开销的选项:
--track-origins=yes会大幅增加内存占用,若不是必须排查未初始化内存问题,可暂时移除;--leak-check=full改为--leak-check=summary,先优先定位段错误,后续再做完整泄漏检查。修改后的命令:valgrind --leak-check=summary --log-file=valgrind-out.txt ./mainCPU -ellpack - 限制调用栈深度:用
--num-callers=N减少调用栈的记录条数(默认12,可改为5),降低内存消耗:valgrind --num-callers=5 --leak-check=summary --log-file=valgrind-out.txt ./mainCPU -ellpack
- 关闭高内存开销的选项:
增加系统可用内存
- 关闭当前系统中闲置的进程、服务,释放内存;
- 临时扩容交换分区(swap):
使用完成后清理:sudo fallocate -l 8G /tmp/swapfile sudo chmod 600 /tmp/swapfile sudo mkswap /tmp/swapfile sudo swapon /tmp/swapfilesudo swapoff /tmp/swapfile && sudo rm /tmp/swapfile
二、确保Valgrind被杀死前能输出部分日志
OOM Killer直接终止进程时,Valgrind可能来不及写入完整日志,可通过以下方式优化日志输出:
- 强制固定日志文件名并刷新缓冲区:用
--log-file-exactly=valgrind-out.txt替代--log-file,强制使用指定文件名,同时Valgrind会更频繁地刷新日志缓冲区; - 实时输出到终端+写入文件:放弃单独写入文件,让Valgrind直接输出到终端,同时把内容写入文件,即使进程被杀死,也能保留已输出的内容:
valgrind --leak-check=summary ./mainCPU -ellpack 2>&1 | tee valgrind-out.txt
三、先快速定位段错误,再用Valgrind细查
如果Valgrind内存占用过高,可先用轻量工具定位段错误大致位置,再针对性排查:
用GDB快速定位段错误:
gdb ./mainCPU run -ellpack程序崩溃时,输入
bt命令查看调用栈,找到触发段错误的代码行,之后再用Valgrind针对相关代码做检查,或缩小测试范围。缩小测试数据:如果程序处理的是大文件/数据集,改用小测试用例运行,降低程序本身的内存占用,进而减少Valgrind的内存消耗。
内容的提问来源于stack exchange,提问作者fabianod

