第49章 malloc() の実装

目次

49.1. _int_malloc() 関数

malloc() を呼び出すのは「 __libc_malloc() 」関数をコールするのと同じことです。

5579 strong_alias (__libc_malloc, __malloc) strong_alias (__libc_malloc, malloc)

この strong_alias は共有ライブラリーのシンボルを指定が可能となっています。

この場合は __libc_malloc のエイリアス(別名)は malloc ということですね。

では __libc_malloc() の中身を確認してみましょう。

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

3026 void *
3027 __libc_malloc (size_t bytes)
3028 {
3029   mstate ar_ptr;
3030   void *victim;
3031
3032   void *(*hook) (size_t, const void *)
3033     = atomic_forced_read (__malloc_hook);
3034   if (__builtin_expect (hook != NULL, 0))
3035     return (*hook)(bytes, RETURN_ADDRESS (0));
3036 #if USE_TCACHE
3037   /* int_free also calls request2size, be careful to not pad twice.  */
3038   size_t tbytes;
3039   checked_request2size (bytes, tbytes);
3040   size_t tc_idx = csize2tidx (tbytes);
3041
3042   MAYBE_INIT_TCACHE ();
3043
3044   DIAG_PUSH_NEEDS_COMMENT;
3045   if (tc_idx < mp_.tcache_bins
3046       /*&& tc_idx < TCACHE_MAX_BINS*/ /* to appease gcc */
3047       && tcache
3048       && tcache->entries[tc_idx] != NULL)
3049     {
3050       return tcache_get (tc_idx);
3051     }
3052   DIAG_POP_NEEDS_COMMENT;
3053 #endif
3054
3055   if (SINGLE_THREAD_P)
3056     {
3057       victim = _int_malloc (&main_arena, bytes);
3058       assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
3059         &main_arena == arena_for_chunk (mem2chunk (victim)));
3060       return victim;
3061     }
3062
3063   arena_get (ar_ptr, bytes);
3064
3065   victim = _int_malloc (ar_ptr, bytes);
3066   /* Retry with another arena only if we were able to find a usable arena
3067      before.  */
3068   if (!victim && ar_ptr != NULL)
3069     {
3070       LIBC_PROBE (memory_malloc_retry, 1, bytes);
3071       ar_ptr = arena_get_retry (ar_ptr, bytes);
3072       victim = _int_malloc (ar_ptr, bytes);
3073     }
3074
3075   if (ar_ptr != NULL)
3076     __libc_lock_unlock (ar_ptr->mutex);
3077
3078   assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
3079           ar_ptr == arena_for_chunk (mem2chunk (victim)));
3080   return victim;
3081 }
3082 libc_hidden_def (__libc_malloc)

シングルスレッドの場合には以下のように _int_malloc() 関数を使い victim に代入したものを返します。

3055   if (SINGLE_THREAD_P)
3056     {
3057       victim = _int_malloc (&main_arena, bytes);
3058       assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
3059         &main_arena == arena_for_chunk (mem2chunk (victim)));
3060       return victim;
3061     }

またこの際には main_arena のアドレスをパラメーターとして _int_malloc() 関数に渡しています。

マルチスレッドであれば以下のように適当なアリーナを arena_get() で見つけます。

3063   arena_get (ar_ptr, bytes);
3064
3065   victim = _int_malloc (ar_ptr, bytes);
3066   /* Retry with another arena only if we were able to find a usable arena
3067      before.  */
3068   if (!victim && ar_ptr != NULL)
3069     {
3070       LIBC_PROBE (memory_malloc_retry, 1, bytes);
3071       ar_ptr = arena_get_retry (ar_ptr, bytes);
3072       victim = _int_malloc (ar_ptr, bytes);
3073     }
3074
3075   if (ar_ptr != NULL)
3076     __libc_lock_unlock (ar_ptr->mutex);
3077
3078   assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
3079           ar_ptr == arena_for_chunk (mem2chunk (victim)));
3080   return victim;

基本的には _int_malloc() を使うのはシングルスレッドと一緒ですが、アリーナは main_arena とは限らないです。

Copyright 2018-2019, by Masaki Komatsu