LoginSignup
2
2

More than 5 years have passed since last update.

aprのメモリプールについて調べてみました。

Last updated at Posted at 2017-12-22

aprのメモリプールについて調べてみました。

apr_palloc
    allocator_alloc
        malloc

という呼び出し階層により、結局はmallocが呼ばれます。
で、どういうタイミングでmallocが呼ばれるのか?1回のmallocで確保されるサイズは?

apr_palloc(pool, n)という呼び出しをした場合、
前回確保したブロックにnバイトの空き領域があれば、そのブロック内から切り出して返します(in apr_palloc):

    /* If the active node has enough bytes left, use it. */
    if (size <= node_free_space(active)) {
        mem = active->first_avail;
        active->first_avail += size;

        return mem;
    }

この記事内ではブロックという用語を使っていますが、apr_memnode_tにほぼ1対1に対応します。aprのソースコードのコメント内でnodeと呼ばれているものと同じです。

前回のブロック内に空き領域が無い、またはn > 8192の場合は、nを4096の倍数に丸めてmallocします(in allocator_alloc)。
8192という数値は、apr_pools.cで定義されている

#define MIN_ALLOC 8192

のようです。

フリーリストは4096の倍数ごとに20個あります:

    /**
     * Lists of free nodes. Slot 0 is used for oversized nodes,
     * and the slots 1..MAX_INDEX-1 contain nodes of sizes
     * (i+1) * BOUNDARY_SIZE. Example for BOUNDARY_INDEX == 12:
     * slot  0: nodes larger than 81920
     * slot  1: size  8192
     * slot  2: size 12288
     * ...
     * slot 19: size 81920
     */
    apr_memnode_t      *free[MAX_INDEX];

検証用に使ったソースコード
https://github.com/aoyama-val/apr_samples/tree/master/2
(LD_PRELOADを使ってmallocにprintfを仕込んでます)

実行すると結果はこうなります:

malloc(1024) = 0x55a223d38260
main
malloc(192) = 0x55a223d38670
malloc(16384) = 0x55a223d38740
malloc(16384) = 0x55a223d3c750
malloc(16384) = 0x55a223d40760
calling apr_palloc(1)
calling apr_palloc(2)
calling apr_palloc(4)
calling apr_palloc(8)
calling apr_palloc(16)
calling apr_palloc(32)
calling apr_palloc(64)
calling apr_palloc(128)
calling apr_palloc(256)
calling apr_palloc(512)
calling apr_palloc(1024)
calling apr_palloc(2048)
calling apr_palloc(4096)
calling apr_palloc(8192)
malloc(16384) = 0x55a223d44770
calling apr_palloc(16384)
malloc(20480) = 0x55a223d48780
calling apr_palloc(32768)
malloc(36864) = 0x55a223d4d790
calling apr_palloc(65536)
malloc(69632) = 0x55a223d567a0
calling apr_palloc(131072)
malloc(135168) = 0x7fbb4237b010
calling apr_palloc(262144)
malloc(266240) = 0x7fbb42335010
calling apr_palloc(524288)
malloc(528384) = 0x7fbb422b3010

8192バイト、思っていたより小さかったことがわかりました(もっと大きくガバッと取っているのかと思ってました)。
そして、これを調べるために最初ソースコードを読んで分からず、次にgdbで動かして分からず。printfを仕込むのが一番効果的でした。

allocator

poolとは別に、allocatorという概念があります。
apr_pool_createすると、通常はglobal_allocatorが使われます。
global_allocatorは、apr_pool_initialize時に作成され、apr_pool_terminate時に破棄されます。つまり、poolの寿命より長いです。
allocatorにはownerとなるpoolがあります。つまりallocatorはあるpoolに「所有」されます。owner poolが破棄されるとき、allocatorも破棄されます。

poolの破棄

apr_pool_destroyを呼ぶとpoolが破棄されます。
poolが確保していたブロックはallocatorのフリーリストに追加され、後にapr_pool_createしたときに再利用されます。

poolの親子関係

poolには親子関係があります。親のpoolが破棄されると、同時に子のpoolも破棄されます。

初期化から終了までの流れ

apr_initialize
    apr_pool_initialize
        - global_allocatorの作成
        - global_poolの作成
apr_pool_create
    - 第2引数で指定されたpool(NULLならglobal_pool)の子としてpoolを作成。global_allocatorを使う。
apr_palloc
    - 必要に応じてmallocする。または既にmallocしてあるブロックから要求されたメモリを切り出して返す
apr_pool_destroy
    - ブロックをallocatorのフリーリストに返す
    - このpoolがallocatorのownerであれば、apr_allocator_destroyを呼ぶ
        - mallocしてあるブロックをfreeする
apr_terminate
    apr_pool_terminate
        - global_poolの破棄(おそらくこのときglobal_allocatorも破棄される)
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2