用Valgrind检测PostgreSQL内存泄露

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: Valgrind简介 Valgrind是一个开源工具集合,其中最有名的是Memcheck可用来检测C,C++程序的内存泄露,判断程序运行是否会crash或者产生不可预知的结果。 Valgrind Memcheck工具的用法 来自Valgrind的quick start manualhttp

Valgrind简介

Valgrind是一个开源工具集合,其中最有名的是Memcheck可用来检测C,C++程序的内存泄露,判断程序运行是否会crash或者产生不可预知的结果。

Valgrind Memcheck工具的用法

以下内容参考自Valgrind的quick start manual
http://www.valgrind.org/docs/manual/quick-start.html

  1. 首先需要准备程序,注意程序编译时必须打开DEBUG,gcc -g参数。同时建议使用-O0编译,以免编译器优化代码后Valgrind无法给出实际的代码位置。
  2. 如果你的程序是这样运行的
myprog arg1 arg2

使用 valgrind 这样运行

Valgrind --leak-check=yes myprog arg1 arg2
The --leak-check option turns on the detailed memory leak detector
  1. 例子
    需要跟踪的程序代码

这部分代码将有两处错误可以被检测到

  #include <stdlib.h>

  void f(void)
  {
     int* x = malloc(10 * sizeof(int));
     x[10] = 0;        // problem 1: heap block overrun
  }                        // problem 2: memory leak -- x not freed

  int main(void)
  {
     f();
     return 0;
  }

跟踪到的结果及解释
第一个错误 heap block overrun

  ==19182== Invalid write of size 4  # 错误类型,一次越界写产生的invalid write
  ==19182==    at 0x804838F: f (example.c:6)   # 下面是进程的stack trace 
  ==19182==    by 0x80483AB: main (example.c:11)
  ==19182==  Address 0x1BA45050 is 0 bytes after a block of size 40 alloc'd    # 描述产生错误的内存地址
  ==19182==    at 0x1B8FF5CD: malloc (vg_replace_malloc.c:130)
  ==19182==    by 0x8048385: f (example.c:5)
  ==19182==    by 0x80483AB: main (example.c:11)
19182表示PID  

第二个错误,内存泄露

  ==19182== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1  # 错误类型,产生内存泄露
  ==19182==    at 0x1B8FF5CD: malloc (vg_replace_malloc.c:130)  # 请忽略该系统调用
  ==19182==    by 0x8048385: f (a.c:5)  # 这里是产生错误的根源
  ==19182==    by 0x80483AB: main (a.c:11)

产生内存泄露的类型非常多,最常见的两种

"definitely lost": your program is leaking memory -- fix it!  必须fix的
"probably lost": your program is leaking memory, unless you're doing funny things with pointers (such as moving them to point to the middle of a heap block).   需要关注的,做一些操作时才会触发。  

如果报了一些未初始化值(uninitialised values)的错误,则需要给valgrind加--track-origins=yes参数,输出更详细的信息来分析。

如何检测PostgreSQL内存泄露

首先需要安装valgrind以及开发包

yum install -y valgrind valgrind-devel

PostgreSQL 9.4开始,内核层面支持valgrind。
编译前需要改一下头文件。

src/include/pg_config_manual.h  

把#define USE_VALGRIND的注释去掉

/*
 * Include Valgrind "client requests", mostly in the memory allocator, so
 * Valgrind understands PostgreSQL memory contexts.  This permits detecting
 * memory errors that Valgrind would not detect on a vanilla build.  See also
 * src/tools/valgrind.supp.  "make installcheck" runs 20-30x longer under
 * Valgrind.  Note that USE_VALGRIND slowed older versions of Valgrind by an
 * additional order of magnitude; Valgrind 3.8.1 does not have this problem.
 * The client requests fall in hot code paths, so USE_VALGRIND also slows
 * native execution by a few percentage points.
 *
 * You should normally use MEMORY_CONTEXT_CHECKING with USE_VALGRIND;
 * instrumentation of repalloc() is inferior without it.
 */
#define USE_VALGRIND

/*
 * Define this to check memory allocation errors (scribbling on more
 * bytes than were allocated).  Right now, this gets defined
 * automatically if --enable-cassert or USE_VALGRIND.
 */
#if defined(USE_ASSERT_CHECKING) || defined(USE_VALGRIND)
#define MEMORY_CONTEXT_CHECKING
#endif

编译参数

CFLAGS=-O0 ./configure --prefix=/home/digoal/pgsql9.5 --enable-debug
gmake world -j 32
gmake install-world -j 32

确认编译正确

$ pg_config

得到如下结果

CFLAGS = -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Wendif-labels -Wmissing-format-attribute -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -g -O0

启用Valgrind调试PostgreSQL

初始化数据库集群,配置数据库配置文件等,略。
使用 Valgrind启动数据库(需要指定PostgreSQL源码中的src/tools/valgrind.supp,这个文件是按照Valgrind提供的格式写的,有兴趣可以研究一下它的内容)

$ cd postgresql-9.5.3_src/

$ valgrind --leak-check=yes --gen-suppressions=all \
    --suppressions=src/tools/valgrind.supp --time-stamp=yes \
    --log-file=/tmp/%p.log --trace-children=yes \
    --track-origins=yes --read-var-info=yes \
    --show-leak-kinds=all -v \
    postgres --log_line_prefix="%m %p " \
    --log_statement=all --shared_buffers=4GB 2>&1 | tee /tmp/postmaster.log

启动会非常慢,等待它启动完成。  

Valgrind的参数略
Valgrind --help

regresstest模式

另外开启一个会话

cd postgresql-9.5.3_src  
make installcheck  

观察 --log-file=/tmp/%p.log 日志

用户定制调试

另外开启一个会话
查询backend pid

select * from pg_backend_pid();

输入需要测试的SQL

观察pid对应的 --log-file=/tmp/%p.log 日志

小结

参考

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
相关文章
|
2月前
|
缓存 监控 Python
在Python中,如何检测和处理内存泄漏?
【2月更文挑战第7天】【2月更文挑战第18篇】在Python中,如何检测和处理内存泄漏?
|
3月前
|
安全 Linux 编译器
内存泄漏检测组件的分析与实现(linux c)-mtrace工具使用
内存泄漏产生原因 在堆上使用malloc/remalloc/calloc分配了内存空间,但是没有使用free释放对应的空间。
75 0
|
3月前
|
Java C++
动手实现内存泄漏检测组件
动手实现内存泄漏检测组件
33 1
|
3月前
使用mtrace进行内存泄漏检测
使用mtrace进行内存泄漏检测
74 1
|
3月前
|
调度 C语言
内存泄漏检测相关内容
内存泄漏检测相关内容
25 0
|
29天前
|
IDE Linux 开发工具
内存泄漏检测工具Valgrind:C++代码问题检测的利器(一)
内存泄漏检测工具Valgrind:C++代码问题检测的利器
65 0
|
25天前
|
缓存 Linux iOS开发
【C/C++ 集成内存调试、内存泄漏检测和性能分析的工具 Valgrind 】Linux 下 Valgrind 工具的全面使用指南
【C/C++ 集成内存调试、内存泄漏检测和性能分析的工具 Valgrind 】Linux 下 Valgrind 工具的全面使用指南
62 1
|
29天前
|
缓存 测试技术 开发工具
内存泄漏检测工具Valgrind:C++代码问题检测的利器(二)
内存泄漏检测工具Valgrind:C++代码问题检测的利器
35 0
|
1月前
|
Python
在Python中,如何检测和修复内存泄漏?
在Python中,如何检测和修复内存泄漏?
81 0
|
3月前
|
Web App开发 前端开发 JavaScript
JavaScript 内存泄漏的检测与防范:让你的程序更稳定
JavaScript 内存泄漏的检测与防范:让你的程序更稳定
JavaScript 内存泄漏的检测与防范:让你的程序更稳定