第30章 アリーナオブジェクト( main_arena / malloc_state )

 malloc_state はアリーナを抽象化した構造体です。

 さらに malloc_state のスタティックオブジェクトにしたものが main_arena です。

 この main_arena は malloc() を使わなくても自動に割り当てされます。

empty.c. 

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

empty.c の GDB デバッグ. 

$ gcc empty.c -g
$ gdb ./a.out
(gdb) break main
(gdb) run
Breakpoint 1, main () at empty.c:2
2         return 0;
(gdb) info proc mappings
process 2792
Mapped address spaces:
          Start Addr           End Addr       Size     Offset objfile
      0x555555554000     0x555555555000     0x1000        0x0 /home/komatsu/system_c_programming/mmap-book/arena/a.out
      0x555555754000     0x555555755000     0x1000        0x0 /home/komatsu/system_c_programming/mmap-book/arena/a.out
      0x555555755000     0x555555756000     0x1000     0x1000 /home/komatsu/system_c_programming/mmap-book/arena/a.out
      0x7ffff75db000     0x7ffff75de000     0x3000        0x0 /lib/x86_64-linux-gnu/libdl-2.27.so
      0x7ffff75de000     0x7ffff77dd000   0x1ff000     0x3000 /lib/x86_64-linux-gnu/libdl-2.27.so
      0x7ffff77dd000     0x7ffff77de000     0x1000     0x2000 /lib/x86_64-linux-gnu/libdl-2.27.so
      0x7ffff77de000     0x7ffff77df000     0x1000     0x3000 /lib/x86_64-linux-gnu/libdl-2.27.so
      0x7ffff77df000     0x7ffff79c6000   0x1e7000        0x0 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff79c6000     0x7ffff7bc6000   0x200000   0x1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff7bc6000     0x7ffff7bca000     0x4000   0x1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff7bca000     0x7ffff7bcc000     0x2000   0x1eb000 /lib/x86_64-linux-gnu/libc-2.27.so
      0x7ffff7bcc000     0x7ffff7bd0000     0x4000        0x0
      0x7ffff7bd0000     0x7ffff7bd4000     0x4000        0x0 /home/komatsu/stderred/build/libstderred.so
      0x7ffff7bd4000     0x7ffff7dd3000   0x1ff000     0x4000 /home/komatsu/stderred/build/libstderred.so
      0x7ffff7dd3000     0x7ffff7dd4000     0x1000     0x3000 /home/komatsu/stderred/build/libstderred.so
      0x7ffff7dd4000     0x7ffff7dd5000     0x1000     0x4000 /home/komatsu/stderred/build/libstderred.so
      0x7ffff7dd5000     0x7ffff7dfc000    0x27000        0x0 /lib/x86_64-linux-gnu/ld-2.27.so
      0x7ffff7fd1000     0x7ffff7fd4000     0x3000        0x0
      0x7ffff7ff5000     0x7ffff7ff7000     0x2000        0x0
      0x7ffff7ff7000     0x7ffff7ffa000     0x3000        0x0 [vvar]
      0x7ffff7ffa000     0x7ffff7ffc000     0x2000        0x0 [vdso]
      0x7ffff7ffc000     0x7ffff7ffd000     0x1000    0x27000 /lib/x86_64-linux-gnu/ld-2.27.so
      0x7ffff7ffd000     0x7ffff7ffe000     0x1000    0x28000 /lib/x86_64-linux-gnu/ld-2.27.so
      0x7ffff7ffe000     0x7ffff7fff000     0x1000        0x0
      0x7ffffffde000     0x7ffffffff000    0x21000        0x0 [stack]
  0xffffffffff600000 0xffffffffff601000     0x1000        0x0 [vsyscall]

(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}
(gdb) p &main_arena
$2 = (struct malloc_state *) 0x7ffff7bcac40 <main_arena>
(gdb) p *((struct malloc_state *)0x7ffff7bcac40)
$4 = {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}

 アリーナのアドレス「 0x7ffff7bcac40 」は main_arena においては「 libc.2.27.so 」の中にあります。

0x7ffff7bca000     0x7ffff7bcc000     0x2000   0x1eb000 /lib/x86_64-linux-gnu/libc-2.27.so

 これを図にすると以下のようになります。

図30.1 メインアリーナ(main_arena)

img/main_arena.png

 fastbinsY は小さめのフリーチャンクを指すポインター、 bins は大きめのフリーチャンクを指すポインターとなっています。

 top はトップチャンク(各アリーナに残された未使用メモリー領域)を指すポインターです。

 メインアリーナの特徴はプロセスに一つしかなく、ヒープも一つしかありません。

 そのためアリーナを抽象化したオブジェクトである malloc_state は一つしかないですし、ヒープを抽象化した heap_info オブジェクトは無いです。

 この理由はメインアリーナはシングルスレッドを想定した作りになっているからです。

 ではマルチスレッドが前提のスレッドアリーナはどうなのか図で確認してみましょう。

図30.2 スレッドアリーナ

img/thread_arena.png

 画像書きながらイマイチだな〜と思うんですが、正直このレベルの複雑さのオブジェクトを表すには言葉が不可欠なんじゃマイカと思うわけです。

 例えば heap_info は次の項目で詳しく説明するんで、先走って説明してるようなトンチンカンな説明をしてる気分にさせられんですよね。

 それで heap_info はヒープを抽象化したもので、ヒープの先頭にきます。

 スレッドアリーナの特性は、複数のヒープを持つことが可能ですんで一つのスレッドアリーナには heap_info が複数あると考えてもよろしいかと思います。

 それと malloc_state は(libc.so の中に割り当てられた) main_arena と違って heap_info のすぐ次に配置されます。

 では定義を見てみましょう。

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

1674 struct malloc_state
1675 {
1676   /* Serialize access.  */
1677   __libc_lock_define (, mutex);
1678
1679   /* Flags (formerly in max_fast).  */
1680   int flags;
1681
1682   /* Set if the fastbin chunks contain recently inserted free blocks.  */
1683   /* Note this is a bool but not all targets support atomics on booleans.  */
1684   int have_fastchunks;
1685
1686   /* Fastbins */
1687   mfastbinptr fastbinsY[NFASTBINS];
1688
1689   /* Base of the topmost chunk -- not otherwise kept in a bin */
1690   mchunkptr top;
1691
1692   /* The remainder from the most recent split of a small request */
1693   mchunkptr last_remainder;
1694
1695   /* Normal bins packed as described above */
1696   mchunkptr bins[NBINS * 2 - 2];
1697
1698   /* Bitmap of bins */
1699   unsigned int binmap[BINMAPSIZE];
1700
1701   /* Linked list */
1702   struct malloc_state *next;
1703
1704   /* Linked list for free arenas.  Access to this field is serialized
1705      by free_list_lock in arena.c.  */
1706   struct malloc_state *next_free;
1707
1708   /* Number of threads attached to this arena.  0 if the arena is on
1709      the free list.  Access to this field is serialized by
1710      free_list_lock in arena.c.  */
1711   INTERNAL_SIZE_T attached_threads;
1712
1713   /* Memory allocated from the system in this arena.  */
1714   INTERNAL_SIZE_T system_mem;
1715   INTERNAL_SIZE_T max_system_mem;
1716 };

 この中には mchunkptr という型がありますが、これは malloc_chunk 型を指すポインターです。

 malloc_chunk 型はデータを保管したり空き領域を管理する役割を持ちますが、これは後のチャンクの項目で説明しますね。

 malloc_state 構造体のポインターには別名として mstate があります。

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

 14 struct malloc_state;
 15 typedef struct malloc_state *mstate;

 それと main_arena については以下のように malloc_state 型として定義されていますね。

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

1755 /* There are several instances of this struct ("arenas") in this
1756    malloc.  If you are adapting this malloc in a way that does NOT use
1757    a static or mmapped malloc_state, you MUST explicitly zero-fill it
1758    before using. This malloc relies on the property that malloc_state
1759    is initialized to all zeroes (as is true of C statics).  */
1760
1761 static struct malloc_state main_arena =
1762 {
1763   .mutex = _LIBC_LOCK_INITIALIZER,
1764   .next = &main_arena,
1765   .attached_threads = 1
1766 };

 main_arena をデバッグ開始直後の gdb でチェックできたのはスタティックオブジェクトだからです。

Copyright 2018-2019, by Masaki Komatsu