D言語の配列領域の再確保を調べてみた

#犯行動機、かく語れり
---
　D言語の配列が付け足し等によって、どのように延長されるのか？を試してみました。
　配列を接続した際、メモリがどれだけ慌ただしく動くのか？を知っておきたかったんです。

#検証
---
　内容は至って簡単。

1. byte型動的配列(buffer)に1要素(=1バイト)ずつ足していく。
2. 配列の先頭アドレス(buffer.ptr)からメモリブロック情報(BlkAttr)を、GC.query関数で取り出す。
3. 確保先頭アドレスとその長さが変わったら、標準出力。
4. 出力結果をじっくりたっぷりねぶりあげるように観察。

　テストコードは以下のとおり。

```d:testcode.d
import
    core.memory ,
    std.stdio ;

void main()
{
    byte[] buffer;
    void*  base = GC.query(buffer.ptr).base;
    size_t size = GC.query(buffer.ptr).size;
    
    writefln( "length=% 8d, ptr=xxxxxxxx -> %08X, length=% 8d",
              buffer.length,
              base,
              size
            );
    
    foreach( i ; 0 .. 1024*1024 ){
        buffer ~= 0;
        
        auto bi = GC.query(buffer.ptr);
        
        if( base != bi.base || size != bi.size ){
            writefln( "length=% 8d, ptr=%08X -> %08X, length=% 8d(% +8d)",
                      buffer.length,
                      base,
                      bi.base,
                      bi.size,
                      bi.size - size
                    );
            base = bi.base;
            size = bi.size;
        }
    }
}
```

#結果
---
> output:
> length=       0, ptr=xxxxxxxx -> null, length=       0
> length=       1, ptr=null -> 009D1FE0, length=      16(     +16)
> length=      16, ptr=009D1FE0 -> 009D2FE0, length=      32(     +16)
> length=      32, ptr=009D2FE0 -> 009D3FC0, length=      64(     +32)
> length=      64, ptr=009D3FC0 -> 009D0F00, length=     128(     +64)
> length=     128, ptr=009D0F00 -> 009D4F00, length=     256(    +128)
> length=     256, ptr=009D4F00 -> 009D5E00, length=     512(    +256)
> length=     511, ptr=009D5E00 -> 009D6C00, length=    1024(    +512)
> length=    1023, ptr=009D6C00 -> 009D7800, length=    2048(   +1024)
> length=    2047, ptr=009D7800 -> 00BD0000, length=    4096(   +2048)
> length=    4080, ptr=00BD0000 -> 00BD0000, length=    8192(   +4096)
> length=    8176, ptr=00BD0000 -> 00BD0000, length=   16384(   +8192)
> length=   16368, ptr=00BD0000 -> 00BD0000, length=   28672(  +12288)
> length=   28656, ptr=00BD0000 -> 00BD0000, length=   49152(  +20480)
> length=   49136, ptr=00BD0000 -> 00BD0000, length=   65536(  +16384)
> length=   65520, ptr=00BD0000 -> 00BD0000, length=   69632(   +4096)
> length=   69616, ptr=00BD0000 -> 00BD0000, length=  110592(  +40960)
> length=  110576, ptr=00BD0000 -> 00BD0000, length=  131072(  +20480)
> length=  131056, ptr=00BD0000 -> 00BD0000, length=  135168(   +4096)
> length=  135152, ptr=00BD0000 -> 00BD0000, length=  212992(  +77824)
> length=  212976, ptr=00BD0000 -> 00BD0000, length=  262144(  +49152)
> length=  262128, ptr=00BD0000 -> 00BD0000, length=  266240(   +4096)
> length=  266224, ptr=00BD0000 -> 00BD0000, length=  405504( +139264)
> length=  405488, ptr=00BD0000 -> 00BD0000, length=  458752(  +53248)
> length=  458736, ptr=00BD0000 -> 00BD0000, length=  462848(   +4096)
> length=  462832, ptr=00BD0000 -> 00BD0000, length=  704512( +241664)
> length=  704496, ptr=00BD0000 -> 00BD0000, length=  720896(  +16384)
> length=  720880, ptr=00BD0000 -> 00CD0000, length= 1081344( +360448)

#推察(ソースを見ずに)
---
1. アロケーション領域をその場から伸張できる場合、伸ばす（自動で伸ばす長さに法則性が見出だせず）。
2. 伸張できない場合、再確保+配列コピーを実施。

#まだ調べたいこと
---
　マルチスレッド環境下でのアロケーション性能とかも気になる所。とはいえ、実行速度にセンシティブな運用（ゲームユースとか）だと、アロケーション系命令の実行機会最小化を目指す工夫が必要かも。