第29章 アリーナによるマルチスレッド対応

 アリーナは malloc をマルチスレッド対応するために作った仕組みです。

 アリーナは malloc が使う 3 つの階層の最上位の構造体みたいなものです。

アリーナ
1 スレッドに一つ存在(木の幹さながらに元になる)
ヒープ
1 アリーナに複数のヒープが存在(木の枝さながらに木の幹から分かれる)
チャンク
1 ヒープに複数のチャンクが存在(木の葉や果実さながらに木の枝から分かれる実・データの部分)

 アリーナからヒープ、ヒープからチャンクというように分岐していき、単位が小さくなると考えれば良いでしょう。

 ちなみにチャンクは単にメモリー領域を割り当てただけのアドレス範囲に過ぎませんが大きく分けると 2 種類が存在しますね。

割り当て済みチャンク
malloc() で割り当てたチャンク。データ領域がある
フリーチャンク
free() 関数で解放された未使用のチャンク。再利用を可能にするために連結構造のリンクが張り巡らされている
トップチャンク
各アリーナに残された未使用メモリー領域

 原則としてスレッドに一つアリーナがあるみたいな考えで良いです。

 アリーナにはスレッドロックの機能がついているので、アリーナにアクセスするには一部の領域を除いて、複数のスレッドからの同時処理がおきないように排他制御されます。

 まあCPUコアの 8 倍がアリーナ数の限度らしいとも聞くので、スレッドを増やしすぎるとアリーナへのアクセスが混雑するらしいです。

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

#define NARENAS_FROM_NCORES(n) ((n) * (sizeof (long) == 4 ? 2 : 8))

 このマクロは 32 ビットなら CPU コア数の 2 倍が限度で 64 ビットなら CPU コア数の 8 倍が限度となります。

 それでアリーナには 2 種類があります。

メインアリーナ
brk() で割り当て。ヒープ領域に割り当て。スレッドセーフ。
スレッドアリーナ
mmap() で割り当て。スレッドセーフ。複数のヒープ領域を持つことができる。

 メインアリーナのインスタンス( main_arena )はプログラムを実行すると自動的に作られます。

main_arena
malloc_state スタティックオブジェクト

 この main_arena の中身は malloc() をコールするであっても GDB でチェックです。

empty.c. 

  1 int main(){
  2   return 0;
  3 }

ビルドと実行結果. 

$ gcc empty.c -g
$ gdb ./a.out
(gdb) break main
(gdb) run
Breakpoint 1, main () at empty.c:2
2         return 0;
(gdb) p main_arena
$1 = {mutex = 0, flags = 0, have_fastchunks = 0, fastbinsY = {0x0, 0x0, 0x0,
    0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, top = 0x0, last_remainder = 0x0,
  bins = {0x0 <repeats 254 times>}, binmap = {0, 0, 0, 0},
  next = 0x7ffff7bcac40 <main_arena>, next_free = 0x0, attached_threads = 1,
  system_mem = 0, max_system_mem = 0}

 mutex というのが同時アクセスからロックするための排他制御オブジェクトですね、

 flag とか bins とか next とかありますが、これは後で説明しますね。

 スレッドアリーナは mmap() が割り当てるメモリー領域に作られます。

img/process_address_space_brk.png

 図の「紐付けられた領域」の部分がスレッドアリーナに割り当てられます。

 まあ mmap() は後で詳しく説明しますね。

 それで malloc は C 言語で記述されているので、ソースコードを読めば挙動はわかりますが、その中でも抑えておきたいものが以下のリストです。

malloc_state
アリーナを抽象化した構造体
heap_info
ヒープを抽象化した構造体
malloc_chunk
チャンクを抽象化した構造体
malloc_par
malloc の環境変数を記述する構造体
tcache_perthread_struct
スレッドキャッシュを抽象化した構造体

 特に malloc_state / heap_info / malloc_chunk は malloc() の理解をする上で不可欠となります。

Copyright 2018-2019, by Masaki Komatsu