無料Wikiサービス | デモページ
Linuxなどのメモ書き

glibc ヒープ領域の縮退


概要

mysqlコマンドで大量のレコードを取得中に、psコマンドでメモリの使用量を見ていたらクエリ実行中はVSZ(仮想アドレス空間のサイズ)がじわじわと増え続けていたが、クエリの実行が完了するとVSZのサイズが小さくなった。

(だいぶ前の)libcではmalloc()してヒープ領域が拡張されたら、free()してもバッファがFreeListに返されるだけで、ヒープ領域はそのままであったため、VSZのサイズが小さくなることはなかったと思ったが、最近ではちゃんとヒープ領域を縮退してくれるらしい。少し調査。

glibcのソース

glibc-2.4.tar.gzのソースを確認してみる。詳しくは追っていないが、以下のような流れで縮退処理に行っている。grow_heap()にはマイナスの引数を渡して縮退させている。

free() => public_fREe() => _int_free() => heap_trim() => grow_heap()

実際の挙動

実際にmalloc()&free()してプロセスのアドレス空間のサイズの動きを見てみた。以下のソースは1kbのメモリを20k個確保(合計20M)して解放する。(使用したライブラリはglibc 2.3.5)

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

#define BUFFCNT  (20*1024)
#define BUFFSIZE (1024)
void *buffp[BUFFCNT];

main()
{
        void *p;
        int i;

        for (i = 0 ; i < BUFFCNT ; i++) {
                if (!(buffp[i] = malloc(BUFFSIZE)))
                        return -1;
        }

        sleep(5);

        printf("free\n");
        for (i = 0 ; i < BUFFCNT; i++)
                free(buffp[i]);

        while (1) {
                sleep(1);
        }
}
このプログラムを実行してps -auxでVSZの変化を見てみると、malloc後はVSZは20M+となり、freeしたらVSZが小さくなって、ヒープ領域がちゃんと縮退されているのがわかる。
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
malloc後
tomita    5759  0.6  2.1  22216 21048 pts/9    S+   14:35   0:00 ./a.out
free後
tomita    5759  0.6  0.0   1628   572 pts/9    S+   14:35   0:00 ./a.out

また、以下のようにして末尾のバッファをfreeしないと、ヒープ領域の末尾にバッファが残るので縮退はされない。
for (i = 0 ; i < BUFFCNT - 1; i++)
    free(buffp[i]);


捕捉

FreeBSDでもCVSを見ると2006/4/27 Rev.1.125でデータセグメントを縮小するように修正されているっぽい(参照)。

最終更新 2006/10/02 21:30:37 - kztomita
(2006/09/29 14:31:15 作成)