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

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

```
apr_palloc
    allocator_alloc
        malloc
```

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

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

```c
    /* 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で定義されている

```c
#define MIN_ALLOC 8192
```

のようです。

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

```c
    /**
     * 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も破棄される）
```