MALLOC_MMAP_THRESHOLD_ と MALLOC_MMAP_MAX_


malloc(3)を呼んだ時、glibcはヒープ領域から指定したサイズのチャンクを確保するが、ヒープ領域が足りなかった場合glibcはbrk(2)を呼んでヒープ領域を拡張するか、Anonymous Memoryと呼ばれる領域をmmap(2)して新たなヒープ領域を確保する。

この動作を制御する環境変数がMALLOC_MMAP_THRESHOLD_らしいのでこれを試しているのだけれど、効かなくて困った。

しかたがないのでglibcのソースを読んでいるとmmap(2)を使用する最大サイズを指定するMALLOC_MMAP_MAX_というのも見つけた、これはばっちり効いたのでこれを使おう。

1M を 3回 malloc するだけのコード

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

int main(){
    int i;
    for(i=0;i<3;i++){
        malloc(1*1024*1024);
    }
    return 0;
}
% strace ./a.out
(略)
mmap2(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7c9b000
mmap2(NULL, 2101248, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7a9a000
mmap2(NULL, 3149824, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7799000

既定では3回mmap(2)してる。 MALLOC_MMAP_MAX_=0するとbrk(2)をだけを呼ぶようになった。 MALLOC_MMAP_MAX_=1にすると、

% strace env MALLOC_MMAP_MAX_=1 ./a.out
(略)
mmap2(NULL, 1052672, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7cfe000
brk(0)                                  = 0x94bc000
brk(0x95dd000)                          = 0x95dd000
brk(0x96dd000)                          = 0x96dd000

最初のmalloc(3)だけmmap(2)した。 単位はMbyte なのね。(MALLOC_TRIM_THRESHOLD_の単位は byte だったのに…)

これで完全に malloc(3) の中で mmap(2) を呼ぶこと無いかというと、そういう訳でもなくて、特定の条件下で mmap(2) する場合ある様なので困ったな。