次の様なC++プログラムのソースをgcc5.1でコンパイルする。
int main () {}
g++ ./a.cpp
valgrindでメモリリークをチェックしてみる。
==32488== HEAP SUMMARY:
==32488== in use at exit: 72,704 bytes in 1 blocks
==32488== total heap usage: 1 allocs, 0 frees, 72,704 bytes allocated
==32488==
==32488== LEAK SUMMARY:
==32488== definitely lost: 0 bytes in 0 blocks
==32488== indirectly lost: 0 bytes in 0 blocks
==32488== possibly lost: 0 bytes in 0 blocks
==32488== still reachable: 72,704 bytes in 1 blocks
==32488== suppressed: 0 bytes in 0 blocks
==32488== Rerun with --leak-check=full to see details of leaked memory
==32488==
==32488== For counts of detected and suppressed errors, rerun with: -v
==32488== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 5 from 5)
7Kバイト以上ヒープが使われていて、しかも回収はOSに投げている。
gcc5.1以外ではそんな事起きない。
objdump見ても、何も変な事はしていない。
cプログラムとしてコンパイルすると、アロケートされない。
あ、そういえばgcc5.1からlibsupc++が変わったんだったな・・・
ちなみに、私の環境では-O3
でコンパイルして、この空のプログラムを実行するとsystime以外で4msもかかる。前は0ms以下だった。
ふざけんな。
原因
多分だけど、libsupc++はメモリを使いきった時でも例外を補足できるようにあらかじめバッファを確保しているっぽい。
ただ、並列環境で大量にスレッド立ててると、メモリ使いきった時に例外がスレッドの数だけ投げられてくる可能性があるので、それだともっと大きなバッファ必要じゃね?ってなって、だったらヒープの方が良いだろうとgccの開発者達は思ったらしい。
ちなみに、バッファの部分のコードはここにある。
抜粋すると
115 arena_size = (EMERGENCY_OBJ_SIZE * EMERGENCY_OBJ_COUNT
116 + EMERGENCY_OBJ_COUNT * sizeof (__cxa_dependent_exception));
ここでバッファのサイズを計算するとちょうど、valgrindの結果と合う。
でも、流石にオーバーヘッドでかすぎだと思う。
libc++は大丈夫です。