第37章 ビンのインデックスの計算

目次

37.1. 32 ビットアーキテクチャのビン
37.2. 64 ビットアーキテクチャのビン

 ビンのインデックスの計算は、想像するより複雑になっています。

 なので、ちょこっと説明をさせて頂きますね。

 まずインデックスを計算するために必要な環境変数を malloc.c のソースコードを読みながら考えてきましょう。

malloc.c(https://github.com/MacKomatsu/glibc/blob/release/2.27/master/malloc/malloc-internal.h). 

 54 #ifndef INTERNAL_SIZE_T
 55 # define INTERNAL_SIZE_T size_t
 56 #endif
 57
 58 /* The corresponding word size.  */
 59 #define SIZE_SZ (sizeof (INTERNAL_SIZE_T))

 SIZE_SZ は size_t 型のバイトサイズと同じです。

malloc.c(https://github.com/MacKomatsu/glibc/blob/release/2.27/master/malloc/malloc.c). 

1460 #define NBINS             128
1461 #define NSMALLBINS         64
1462 #define SMALLBIN_WIDTH    MALLOC_ALIGNMENT
1463 #define SMALLBIN_CORRECTION (MALLOC_ALIGNMENT > 2 * SIZE_SZ)
1464 #define MIN_LARGE_SIZE    ((NSMALLBINS - SMALLBIN_CORRECTION) * SMALLBIN_WIDTH)
1465

 64 ビットアーキテクチャだと size_t のサイズは 8 バイトになるはずですから MALLOC_ALIGNMENT は 16 となり SIZE_SZ は 8 となりますね。

 であれば MIN_LARGE_SIZE は (64 - 0) * 16 = 1024 となります。

 32 ビットアーキテクチャだと size_t のサイズは 4 バイトだとして MALLOC_ALIGNMENT は 8 バイトになり SIZE_SZ は 4 になります。

 その場合の MIN_LARGE_SIZE は (64 - 0) * 8 = 512 です。

malloc.c(https://github.com/MacKomatsu/glibc/blob/release/2.27/master/malloc/malloc.c). 

1466 #define in_smallbin_range(sz)  \
1467   ((unsigned long) (sz) < (unsigned long) MIN_LARGE_SIZE)
1468
1469 #define smallbin_index(sz) \
1470   ((SMALLBIN_WIDTH == 16 ? (((unsigned) (sz)) >> 4) : (((unsigned) (sz)) >> 3))\
1471    + SMALLBIN_CORRECTION)
1472

 in_smallbin_range は Small bin の範囲内にあるかチェックするマクロです。

 つまり 64 ビットアーキテクチャだと 1024 バイトが範囲内となります。

 Small Bin か否かは「 sz < MIN_LARGE_SIZE 」の結果によって決定されるってことです。

 smallbin_index(sz) は MALLOC_ALIGNMENT が 16 バイトであれば「 sz ÷ 16 」になりますね。

 16, 32, 48, 64, …, 1008 バイトてな感じになるはずです。

 1008 は 1024 - 16 の意味です。

 最大値と一緒になると微妙なので… (´・ω・`)

 MALLOC_ALIGNMNET が 8 バイトなら「 sz ÷ 8 」となり、インデックスの間隔がアーキテクチャによって変動します。

 16, 24, 32, 40, 48, …, 504 バイトでしょうかね…

 最後の値は単に最大値が 512 なので、その直前の 8 の倍数をとっただけです。

 これに smallbin_index(sz) を使ってインデックスに翻訳すると 1, 2, 3, …, 63 でしょうかね。

 次は Large bin のインデックスの計算を見てみましょう。

malloc.c(https://github.com/MacKomatsu/glibc/blob/release/2.27/master/malloc/malloc.c). 

1473 #define largebin_index_32(sz)                                                \
1474   (((((unsigned long) (sz)) >> 6) <= 38) ?  56 + (((unsigned long) (sz)) >> 6) :\
1475    ((((unsigned long) (sz)) >> 9) <= 20) ?  91 + (((unsigned long) (sz)) >> 9) :\
1476    ((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
1477    ((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
1478    ((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
1479    126)
1480
1481 #define largebin_index_32_big(sz)                                            \
1482   (((((unsigned long) (sz)) >> 6) <= 45) ?  49 + (((unsigned long) (sz)) >> 6) :\
1483    ((((unsigned long) (sz)) >> 9) <= 20) ?  91 + (((unsigned long) (sz)) >> 9) :\
1484    ((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
1485    ((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
1486    ((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
1487    126)
1488
1489 // XXX It remains to be seen whether it is good to keep the widths of
1490 // XXX the buckets the same or whether it should be scaled by a factor
1491 // XXX of two as well.
1492 #define largebin_index_64(sz)                                                \
1493   (((((unsigned long) (sz)) >> 6) <= 48) ?  48 + (((unsigned long) (sz)) >> 6) :\
1494    ((((unsigned long) (sz)) >> 9) <= 20) ?  91 + (((unsigned long) (sz)) >> 9) :\
1495    ((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
1496    ((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
1497    ((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
1498    126)
1499
1500 #define largebin_index(sz) \
1501   (SIZE_SZ == 8 ? largebin_index_64 (sz)                                     \
1502    : MALLOC_ALIGNMENT == 16 ? largebin_index_32_big (sz)                     \
1503    : largebin_index_32 (sz))
1504

 それで Large bin のインデックスを計算してくれるマクロは large_bin_index(sz) となります。

 64 ビットアーキテクチャだと large_bin_index_64 マクロを実行します。

 32 ビットアーキテクチャでアラインメントが 16 バイトなら largebin_index_32_big(sz) をマクロを実行ですね。

 最後に 32 ビットアーキテクチャで 16 バイトでないなら largebin_index_32(sz) マクロを使います。

Copyright 2018-2019, by Masaki Komatsu