18. valgrind で PostgreSQL のメモリリークをみつけよう - PostgreSQL のソースコードを読む

valgrind については、C(++)言語: valgrindの使い方 を参照。

準備

% sudo apt-get install valgrind
% sudo apt-get install libreadline-dev libz-dev

PostgreSQL 8.3.6 のインストール。

% ./configure --prefix=/tmp/local
% make
% make check

PostgreSQL起動

% /tmp/local/bin/postgres -D /tmp/data
server starting
% /tmp/local/bin/createdb hige
% /tmp/local/bin/psql -n hige

valgrind 経由で起動

起動する。

% valgrind --leak-check=full /tmp/local/bin/postgres -D /tmp/data

別のコンソールから停止。

/tmp/local/bin/pg_ctl -D /tmp/data -l logfile stop

leak 箇所が出ました。

==25137== 39 bytes in 1 blocks are definitely lost in loss record 3 of 12
==25137==    at 0x4C265AE: malloc (vg_replace_malloc.c:207)
==25137==    by 0x556E3F1: strdup (in /lib/libc-2.8.90.so)
==25137==    by 0x68F4FE: set_pglocale_pgservice (in /tmp/local/bin/postgres)
==25137==    by 0x548FC9: main (in /tmp/local/bin/postgres)
==25137==
==25137==
==25137== 3,348 (264 direct, 3,084 indirect) bytes in 1 blocks are definitely lost in loss record 7 of 12
==25137==    at 0x4C265AE: malloc (vg_replace_malloc.c:207)
==25137==    by 0x67F76C: save_ps_display_args (in /tmp/local/bin/postgres)
==25137==    by 0x548FB9: main (in /tmp/local/bin/postgres)

あれれ。ソースコード情報が出ない。デバッグビルドしていなかったからか。

% CFLAGS=-g ./configure --prefix=/tmp/loca

PostgreSQL ビルドし直し。


もう一度。実行。

==7201== 39 bytes in 1 blocks are definitely lost in loss record 3 of 12
==7201==    at 0x4C265AE: malloc (vg_replace_malloc.c:207)
==7201==    by 0x556E3F1: strdup (in /lib/libc-2.8.90.so)
==7201==    by 0x73B48F: set_pglocale_pgservice (exec.c:660)
==7201==    by 0x593656: main (main.c:90)
==7201==
==7201==
==7201== 3,373 (264 direct, 3,109 indirect) bytes in 1 blocks are definitely lost in loss record 7 of 12
==7201==    at 0x4C265AE: malloc (vg_replace_malloc.c:207)
==7201==    by 0x724896: save_ps_display_args (ps_status.c:162)
==7201==    by 0x593641: main (main.c:79)

ソースコード情報(ファイル、行番号)が表示されるようになった。

感じをつかもう

表示されたリークがクリティカルなものかどうかはわからないが、今後の作業で似たようなことを繰り返すであろうから慣れのために調べよう。
GNU global で見ていくと exec.c:660 は以下の通り。

putenv(strdup(env_path));

ふむ。許容範囲な気もするが、putenv の仕様を見てみようか。

string が指している文字列は環境の一部となるので、 文字列を変更すると環境も変更される。

ということなのでありかな。
あとで回収できるように、どこかで参照を残しておくというまじめな方法もあるが、数が少ないのでとりあえずよしとしよう。

今後

postgresql は接続に対して fork するので1接続で大量に select 文などを投げまくってメモリリークが起きていないか調べよう。