在 Postgres C 代码中查找内存泄漏

主要观点:作者花费一周时间寻找 Postgres 的 WAL Sender 进程中的内存泄漏,尝试 Valgrind 和 gcc/clang sanitizers 无果后,偶然发现 bcc 工具集中的 memleak 程序找到了泄漏源。文中详细介绍了 Valgrind、Postgres 中的内存管理(MemoryContext)、设置 Valgrind 包装器、AddressSanitizer 和 LeakSanitizer 以及 eBPF 和 bcc 工具等用于检测内存泄漏的方法和过程。
关键信息

  • 在 Postgres 的 PostgresMain() 函数中添加循环分配内存导致内存泄漏,每次连接客户端发送语句就会分配新的 4KB 块。
  • Valgrind 主要在程序结束时检查泄漏,对 Postgres 中的内存泄漏检测效果不佳,且使用 --leak-check=full 标志时 Postgres 会崩溃。
  • AddressSanitizer 和 LeakSanitizer 可直接集成到 clanggcc 中,通过 -fsanitize=address 编译代码启用,但默认行为是在遇到第一个错误时崩溃,可通过设置环境变量 ASAN_OPTIONS="halt_on_error=false" 让其继续运行。
  • eBPF 和 bcc 工具中的 memleak 程序可用于记录运行程序的内存使用情况和分配来源,通过 sudo /usr/share/bcc/tools/memleak -p [PID] 运行,能准确找到内存泄漏位置及堆栈跟踪。
    重要细节
  • 展示了简单 main.c 程序在使用和不使用 free(x) 时 Valgrind 的检测结果。
  • 介绍了 Postgres 的安装、配置和启动过程,以及在其中引入内存泄漏的方法。
  • 给出了 Valgrind 包装器脚本的内容和使用方法,以及 Postgres 与各种工具结合检测内存泄漏的具体步骤和输出。
阅读 31
0 条评论