49.1. _int_malloc() 関数

注記

malloc コードを読みたい変わり者向けの項目です。正直なところ、暇のある人にしかお薦めできないので、普通に読みた方はスキップした方が良いと思いますぅ… まる (´・ω・`)

_int_malloc() 関数さえ理解できれば malloc() の理解も出来るといえるでしょう。

読むのはガチにむっちゃ大変ですぞ…

(´・ω・`)

まあ一行づつ読み解くのは難しいですが、おおまかにどの箇所がどの処理をしているくらいの説明はやってみたいと思いまする…

(´・ω・`)

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

3515 /*
3516    ------------------------------ malloc ------------------------------
3517  */
3518
3519 static void *
3520 _int_malloc (mstate av, size_t bytes)
3521 {
3522   INTERNAL_SIZE_T nb;               /* normalized request size */
3523   unsigned int idx;                 /* associated bin index */
3524   mbinptr bin;                      /* associated bin */
3525
3526   mchunkptr victim;                 /* inspected/selected chunk */
3527   INTERNAL_SIZE_T size;             /* its size */
3528   int victim_index;                 /* its bin index */
3529
3530   mchunkptr remainder;              /* remainder from a split */
3531   unsigned long remainder_size;     /* its size */
3532
3533   unsigned int block;               /* bit map traverser */
3534   unsigned int bit;                 /* bit map traverser */
3535   unsigned int map;                 /* current word of binmap */
3536
3537   mchunkptr fwd;                    /* misc temp for linking */
3538   mchunkptr bck;                    /* misc temp for linking */
3539
3540 #if USE_TCACHE
3541   size_t tcache_unsorted_count;     /* count of unsorted chunks processed */
3542 #endif
3543
3544   /*
3545      Convert request size to internal form by adding SIZE_SZ bytes
3546      overhead plus possibly more to obtain necessary alignment and/or
3547      to obtain a size of at least MINSIZE, the smallest allocatable
3548      size. Also, checked_request2size traps (returning 0) request sizes
3549      that are so large that they wrap around zero when padded and
3550      aligned.
3551    */
3552
3553   checked_request2size (bytes, nb);
3554

bytes のアラインメントを取ります。

3555   /* There are no usable arenas.  Fall back to sysmalloc to get a chunk from
3556      mmap.  */
3557   if (__glibc_unlikely (av == NULL))
3558     {
3559       void *p = sysmalloc (nb, av);
3560       if (p != NULL)
3561   alloc_perturb (p, bytes);
3562       return p;
3563     }
3564

av が NULL かチェックします。

もし av が NULL なら symalloc() 関数をコールします。

sysmalloc() の割り当てが成功したら alloc_perturb() を呼び出してポインターを返します。

3565   /*
3566      If the size qualifies as a fastbin, first check corresponding bin.
3567      This code is safe to execute even if av is not yet initialized, so we
3568      can try it without checking, which saves some time on this fast path.
3569    */
3570
3571 #define REMOVE_FB(fb, victim, pp)     \
3572   do              \
3573     {             \
3574       victim = pp;          \
3575       if (victim == NULL)       \
3576   break;            \
3577     }             \
3578   while ((pp = catomic_compare_and_exchange_val_acq (fb, victim->fd, victim)) \
3579    != victim);          \
3580

REMOVE_FB マクロを定義しています。

3581   if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ()))
3582     {
3583       idx = fastbin_index (nb);
3584       mfastbinptr *fb = &fastbin (av, idx);
3585       mchunkptr pp;
3586       victim = *fb;
3587
3588       if (victim != NULL)
3589   {
3590     if (SINGLE_THREAD_P)
3591       *fb = victim->fd;
3592     else
3593       REMOVE_FB (fb, pp, victim);
3594     if (__glibc_likely (victim != NULL))
3595       {
3596         size_t victim_idx = fastbin_index (chunksize (victim));
3597         if (__builtin_expect (victim_idx != idx, 0))
3598     malloc_printerr ("malloc(): memory corruption (fast)");
3599         check_remalloced_chunk (av, victim, nb);
3600 #if USE_TCACHE
3601         /* While we're here, if we see other chunks of the same size,
3602      stash them in the tcache.  */
3603         size_t tc_idx = csize2tidx (nb);
3604         if (tcache && tc_idx < mp_.tcache_bins)
3605     {
3606       mchunkptr tc_victim;
3607
3608       /* While bin not empty and tcache not full, copy chunks.  */
3609       while (tcache->counts[tc_idx] < mp_.tcache_count
3610        && (tc_victim = *fb) != NULL)
3611         {
3612           if (SINGLE_THREAD_P)
3613       *fb = tc_victim->fd;
3614           else
3615       {
3616         REMOVE_FB (fb, pp, tc_victim);
3617         if (__glibc_unlikely (tc_victim == NULL))
3618           break;
3619       }
3620           tcache_put (tc_victim, tc_idx);
3621         }
3622     }
3623 #endif
3624         void *p = chunk2mem (victim);
3625         alloc_perturb (p, bytes);
3626         return p;
3627       }
3628   }
3629     }
3630

リクエストサイズに応じたビンにアクセスするためにインデックスを算出します。

ビンの最初のチャンクを削除して、victim がそのチャンクを指すようにします。

victim が NULL ならスモールビン( Small Bin )のチェックに進みます。

victim が NULL でないならチャンクサイズをチェックし、該当するビンにあることを確かめ、そうでないならエラーを投げます。

最後に alloc_perturb() をコールしポインターを返します。

3631   /*
3632      If a small request, check regular bin.  Since these "smallbins"
3633      hold one size each, no searching within bins is necessary.
3634      (For a large request, we need to wait until unsorted chunks are
3635      processed to find best fit. But for small ones, fits are exact
3636      anyway, so we can check now, which is faster.)
3637    */
3638
3639   if (in_smallbin_range (nb))
3640     {
3641       idx = smallbin_index (nb);
3642       bin = bin_at (av, idx);
3643

リクエストサイズがスモールビン( Small Bin )の範囲内に処理されるコードブロックですね。

リクエストサイズに応じたビンにアクセスするためのインデックスを算出します。

3644       if ((victim = last (bin)) != bin)
3645         {

該当するビンにチャンクが存在しない場合は次のケースに飛びます。

last(bin) つまり bin→bk が victim へ代入されますが、もし bin が同じなら malloc_consolidate() 関数をコールしてから、次のケースにスキップします。

3646           bck = victim->bk;
3647     if (__glibc_unlikely (bck->fd != victim))
3648       malloc_printerr ("malloc(): smallbin double linked list corrupted");

bin→bk が bin と違うとするなら、victim→bk→fd と victim が同じかチェックします。

もし同じでないなら malloc_printerr() をコールしてエラーを投げます。

3649           set_inuse_bit_at_offset (victim, nb);

victim の次のチャンクのために PREV_INUSE ビットを設定します。

3650           bin->bk = bck;
3651           bck->fd = bin;

このチャンクをビンのリストから削除します。

3652
3653           if (av != &main_arena)
3654       set_non_main_arena (victim);
3655           check_malloced_chunk (av, victim, nb);

av に応じた適切なアリーナのビットをこのチャンクに設定します。

3656 #if USE_TCACHE
3657     /* While we're here, if we see other chunks of the same size,
3658        stash them in the tcache.  */
3659     size_t tc_idx = csize2tidx (nb);
3660     if (tcache && tc_idx < mp_.tcache_bins)
3661       {
3662         mchunkptr tc_victim;
3663
3664         /* While bin not empty and tcache not full, copy chunks over.  */
3665         while (tcache->counts[tc_idx] < mp_.tcache_count
3666          && (tc_victim = last (bin)) != bin)
3667     {
3668       if (tc_victim != 0)
3669         {
3670           bck = tc_victim->bk;
3671           set_inuse_bit_at_offset (tc_victim, nb);
3672           if (av != &main_arena)
3673       set_non_main_arena (tc_victim);
3674           bin->bk = bck;
3675           bck->fd = bin;
3676
3677           tcache_put (tc_victim, tc_idx);
3678               }
3679     }
3680       }
3681 #endif

TCACHE についての説明は割愛します。

3682           void *p = chunk2mem (victim);
3683           alloc_perturb (p, bytes);
3684           return p;
3685         }
3686     }

後は alloc_perturb() をコールしてポインターを返します。

3687
3688   /*
3689      If this is a large request, consolidate fastbins before continuing.
3690      While it might look excessive to kill all fastbins before
3691      even seeing if there is space available, this avoids
3692      fragmentation problems normally associated with fastbins.
3693      Also, in practice, programs tend to have runs of either small or
3694      large requests, but less often mixtures, so consolidation is not
3695      invoked all that often in most programs. And the programs that
3696      it is called frequently in otherwise tend to fragment.
3697    */
3698
3699   else
3700     {
3701       idx = largebin_index (nb);
3702       if (atomic_load_relaxed (&av->have_fastchunks))
3703         malloc_consolidate (av);
3704     }

bin→bk と bin が同じ場合に呼ばれます。

リクエストサイズに応じた適切なビンのインデックスを算出します。

もし av がファーストチャンク(Fast Bin のチャンク)を保持しているなら malloc_consolidate() を av に対してコールします。

ここまではファーストビン、スモールビンにはチャンクがないか、リクエストサイズが該当しませんでした。

残りはラージビン( Large Bin )だけですね… (´・ω・`)

3705
3706   /*
3707      Process recently freed or remaindered chunks, taking one only if
3708      it is exact fit, or, if this a small request, the chunk is remainder from
3709      the most recent non-exact fit.  Place other traversed chunks in
3710      bins.  Note that this step is the only place in any routine where
3711      chunks are placed in bins.
3712
3713      The outer loop here is needed because we might not realize until
3714      near the end of malloc that we should have consolidated, so must
3715      do so and retry. This happens at most once, and only when we would
3716      otherwise need to expand memory to service a "small" request.
3717    */
3718
3719 #if USE_TCACHE
3720   INTERNAL_SIZE_T tcache_nb = 0;
3721   size_t tc_idx = csize2tidx (nb);
3722   if (tcache && tc_idx < mp_.tcache_bins)
3723     tcache_nb = nb;
3724   int return_cached = 0;
3725
3726   tcache_unsorted_count = 0;
3727 #endif
3728
3729   for (;; )
3730     {

このループではチャンクをビンに挿入していきます。

3731       int iters = 0;
3732       while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))

未整理ビン( Unsorted Bin )にチャンクがないかチェックして victim に代入します。

3733         {
3734           bck = victim->bk;
3735           if (__builtin_expect (chunksize_nomask (victim) <= 2 * SIZE_SZ, 0)
3736               || __builtin_expect (chunksize_nomask (victim)
3737            > av->system_mem, 0))
3738             malloc_printerr ("malloc(): memory corruption");
3739           size = chunksize (victim);
3740

victim のチャンクサイズが 2*SIZE_SZ と最大値の範囲内にあるかチェックし、範囲外であればエラーを投げます。

問題がなければ victim のチャンクサイズが size 変数に代入されます。

3741           /*
3742              If a small request, try to use last remainder if it is the
3743              only chunk in unsorted bin.  This helps promote locality for
3744              runs of consecutive small requests. This is the only
3745              exception to best-fit, and applies only when there is
3746              no exact fit for a small chunk.
3747            */
3748
3749           if (in_smallbin_range (nb) &&
3750               bck == unsorted_chunks (av) &&
3751               victim == av->last_remainder &&
3752               (unsigned long) (size) > (unsigned long) (nb + MINSIZE))
3753             {
3754               /* split and reattach remainder */
3755               remainder_size = size - nb;
3756               remainder = chunk_at_offset (victim, nb);
3757               unsorted_chunks (av)->bk = unsorted_chunks (av)->fd = remainder;
3758               av->last_remainder = remainder;
3759               remainder->bk = remainder->fd = unsorted_chunks (av);
3760               if (!in_smallbin_range (remainder_size))
3761                 {
3762                   remainder->fd_nextsize = NULL;
3763                   remainder->bk_nextsize = NULL;
3764                 }
3765
3766               set_head (victim, nb | PREV_INUSE |
3767                         (av != &main_arena ? NON_MAIN_ARENA : 0));
3768               set_head (remainder, remainder_size | PREV_INUSE);
3769               set_foot (remainder, remainder_size);
3770
3771               check_malloced_chunk (av, victim, nb);
3772               void *p = chunk2mem (victim);
3773               alloc_perturb (p, bytes);
3774               return p;
3775             }

リクエストサイズがスモールビンの範囲内にあり、未整理ビンのチャンクで、チャンクサイズがリクエストサイズ以上で、victim が最後に残っているチャンクである場合には if 文のブロックが処理されます。

2 つのチャンクに分割します。

1 つめのチャンクは alloc_perturb をコールしてから返されます。

3776
3777           /* remove from unsorted list */
3778           unsorted_chunks (av)->bk = bck;
3779           bck->fd = unsorted_chunks (av);
3780

未整理ビン( Unsorted Bin )からチャンクを削除します。

3781           /* Take now instead of binning if exact fit */
3782
3783           if (size == nb)
3784             {
3785               set_inuse_bit_at_offset (victim, size);
3786               if (av != &main_arena)
3787     set_non_main_arena (victim);
3788 #if USE_TCACHE
3789         /* Fill cache first, return to user only if cache fills.
3790      We may return one of these chunks later.  */
3791         if (tcache_nb
3792       && tcache->counts[tc_idx] < mp_.tcache_count)
3793     {
3794       tcache_put (victim, tc_idx);
3795       return_cached = 1;
3796       continue;
3797     }
3798         else
3799     {
3800 #endif
3801               check_malloced_chunk (av, victim, nb);
3802               void *p = chunk2mem (victim);
3803               alloc_perturb (p, bytes);
3804               return p;
3805 #if USE_TCACHE
3806     }
3807 #endif
3808             }

もし victim のチャンクサイズがリクエストサイズと同じなら alloc_perturb をコールしてからポインターを返します。

3809
3810           /* place chunk in bin */
3811
3812           if (in_smallbin_range (size))
3813             {
3814               victim_index = smallbin_index (size);
3815               bck = bin_at (av, victim_index);
3816               fwd = bck->fd;
3817             }

もし victim のチャンクサイズがスモールビン( Small Bin )の範囲内にあるなら、チャンクを該当するスモールビンの HEAD の位置に挿入します。

3818           else
3819             {
3820               victim_index = largebin_index (size);
3821               bck = bin_at (av, victim_index);
3822               fwd = bck->fd;
3823
3824               /* maintain large bins in sorted order */
3825               if (fwd != bck)
3826                 {
3827                   /* Or with inuse bit to speed comparisons */
3828                   size |= PREV_INUSE;
3829                   /* if smaller than smallest, bypass loop below */
3830                   assert (chunk_main_arena (bck->bk));
3831                   if ((unsigned long) (size)
3832           < (unsigned long) chunksize_nomask (bck->bk))
3833                     {
3834                       fwd = bck;
3835                       bck = bck->bk;
3836
3837                       victim->fd_nextsize = fwd->fd;
3838                       victim->bk_nextsize = fwd->fd->bk_nextsize;
3839                       fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
3840                     }
3841                   else
3842                     {
3843                       assert (chunk_main_arena (fwd));
3844                       while ((unsigned long) size < chunksize_nomask (fwd))
3845                         {
3846                           fwd = fwd->fd_nextsize;
3847         assert (chunk_main_arena (fwd));
3848                         }
3849
3850                       if ((unsigned long) size
3851         == (unsigned long) chunksize_nomask (fwd))
3852                         /* Always insert in the second position.  */
3853                         fwd = fwd->fd;
3854                       else
3855                         {
3856                           victim->fd_nextsize = fwd;
3857                           victim->bk_nextsize = fwd->bk_nextsize;
3858                           fwd->bk_nextsize = victim;
3859                           victim->bk_nextsize->fd_nextsize = victim;
3860                         }
3861                       bck = fwd->bk;
3862                     }
3863                 }
3864               else
3865                 victim->fd_nextsize = victim->bk_nextsize = victim;
3866             }
3867
3868           mark_bin (av, victim_index);
3869           victim->bk = bck;
3870           victim->fd = fwd;
3871           fwd->bk = victim;
3872           bck->fd = victim;
3873

ラージビン( Large Bin )にチャンクを挿入します。

まず最後の最少チャンクをチェックします。

次に victim が最後のチャンクより小さい場合は最後の位置に挿入します。

小さくないのであれば、victim 以上のサイズを持つチャンクをループで探索して、挿入します。

もしサイズが同じであれば該当チャンクの次の位置に挿入します。

3874 #if USE_TCACHE
3875       /* If we've processed as many chunks as we're allowed while
3876    filling the cache, return one of the cached ones.  */
3877       ++tcache_unsorted_count;
3878       if (return_cached
3879     && mp_.tcache_unsorted_limit > 0
3880     && tcache_unsorted_count > mp_.tcache_unsorted_limit)
3881   {
3882     return tcache_get (tc_idx);
3883   }
3884 #endif
3885
3886 #define MAX_ITERS       10000
3887           if (++iters >= MAX_ITERS)
3888             break;
3889         }

上記の処理を 10000 回繰り返します。

3890
3891 #if USE_TCACHE
3892       /* If all the small chunks we found ended up cached, return one now.  */
3893       if (return_cached)
3894   {
3895     return tcache_get (tc_idx);
3896   }
3897 #endif

TCACHE は割愛です… (´・ω・`)

3898
3899       /*
3900          If a large request, scan through the chunks of current bin in
3901          sorted order to find smallest that fits.  Use the skip list for this.
3902        */
3903
3904       if (!in_smallbin_range (nb))
3905         {

リクエストサイズがスモールビンの範囲外かチェックします。

3906           bin = bin_at (av, idx);

ラージビンのインデックスを算出します。

3907
3908           /* skip scan if empty or largest chunk is too small */
3909           if ((victim = first (bin)) != bin
3910         && (unsigned long) chunksize_nomask (victim)
3911           >= (unsigned long) (nb))
3912             {

ビンの最初のチャンク(最大のチャンクサイズ)がリクエストサイズより大きいかチェックします。

3913               victim = victim->bk_nextsize;
3914               while (((unsigned long) (size = chunksize (victim)) <
3915                       (unsigned long) (nb)))
3916                 victim = victim->bk_nextsize;
3917

リクエストサイズ以上の最少サイズチャンクを見つけられるまで反復します。

3918               /* Avoid removing the first entry for a size so that the skip
3919                  list does not have to be rerouted.  */
3920               if (victim != last (bin)
3921       && chunksize_nomask (victim)
3922         == chunksize_nomask (victim->fd))
3923                 victim = victim->fd;
3924
3925               remainder_size = size - nb;
3926               unlink (av, victim, bck, fwd);

残りのサイズ( remainder_size )を算出しときます。

unlink をコールして victim をビンから削除します。

3927
3928               /* Exhaust */
3929               if (remainder_size < MINSIZE)
3930                 {
3931                   set_inuse_bit_at_offset (victim, size);
3932                   if (av != &main_arena)
3933         set_non_main_arena (victim);
3934                 }

残りのサイズ( remainder_size )が最少チャンクサイズ(MINSIZE)より小さいなら、一つのチャンクを返します。

3935               /* Split */
3936               else
3937                 {
3938                   remainder = chunk_at_offset (victim, nb);
3939                   /* We cannot assume the unsorted list is empty and therefore
3940                      have to perform a complete insert here.  */
3941                   bck = unsorted_chunks (av);
3942                   fwd = bck->fd;
3943       if (__glibc_unlikely (fwd->bk != bck))
3944         malloc_printerr ("malloc(): corrupted unsorted chunks");
3945                   remainder->bk = bck;
3946                   remainder->fd = fwd;
3947                   bck->fd = remainder;
3948                   fwd->bk = remainder;
3949                   if (!in_smallbin_range (remainder_size))
3950                     {
3951                       remainder->fd_nextsize = NULL;
3952                       remainder->bk_nextsize = NULL;
3953                     }
3954                   set_head (victim, nb | PREV_INUSE |
3955                             (av != &main_arena ? NON_MAIN_ARENA : 0));
3956                   set_head (remainder, remainder_size | PREV_INUSE);
3957                   set_foot (remainder, remainder_size);
3958                 }

残りのサイズ( remainder_size )が最少チャンクサイズ(MINSIZE)以上なら、2 個のチャンクに分割します。

unsorted_chunks(av)→fd→bk == unsorted_chunks(av) かチェックして違うなら、エラーを投げます。

3959               check_malloced_chunk (av, victim, nb);
3960               void *p = chunk2mem (victim);
3961               alloc_perturb (p, bytes);
3962               return p;
3963             }
3964         }

alloc_perturb() をコールした後にポインターを返します。

3965
3966       /*
3967          Search for a chunk by scanning bins, starting with next largest
3968          bin. This search is strictly by best-fit; i.e., the smallest
3969          (with ties going to approximately the least recently used) chunk
3970          that fits is selected.
3971
3972          The bitmap avoids needing to check that most blocks are nonempty.
3973          The particular case of skipping all bins during warm-up phases
3974          when no chunks have been returned yet is faster than it might look.
3975        */
3976
3977       ++idx;
3978       bin = bin_at (av, idx);
3979       block = idx2block (idx);
3980       map = av->binmap[block];
3981       bit = idx2bit (idx);

次のビンを調べるためにインデックスをインクリメントします。

av→binmap を使って空のビンをスキップしていきます。

3982
3983       for (;; )
3984         {
3985           /* Skip rest of block if there are no more set bits in this block.  */
3986           if (bit > map || bit == 0)
3987             {
3988               do
3989                 {
3990                   if (++block >= BINMAPSIZE) /* out of bins */
3991                     goto use_top;
3992                 }
3993               while ((map = av->binmap[block]) == 0);
3994
3995               bin = bin_at (av, (block << BINMAPSHIFT));
3996               bit = 1;
3997             }
3998

ビンマップのビットが該当する(ビンマップの)ブロックにおいて空であるなら use_top にスキップします。

3999           /* Advance to bin with set bit. There must be one. */
4000           while ((bit & map) == 0)
4001             {
4002               bin = next_bin (bin);
4003               bit <<= 1;
4004               assert (bit != 0);
4005             }

ビットが設定されたビンを探索します。(一つはあるはず)

4006
4007           /* Inspect the bin. It is likely to be non-empty */
4008           victim = last (bin);
4009

victim は現在のビンの最後を指させます。

victim は空でないビンの最後のチャンクを指しています。

4010           /*  If a false alarm (empty bin), clear the bit. */
4011           if (victim == bin)
4012             {
4013               av->binmap[block] = map &= ~bit; /* Write through */
4014               bin = next_bin (bin);
4015               bit <<= 1;
4016             }
4017

ビンマップを使って空のビンをスキップします。

4018           else
4019             {
4020               size = chunksize (victim);
4021
4022               /*  We know the first chunk in this bin is big enough to use. */
4023               assert ((unsigned long) (size) >= (unsigned long) (nb));
4024
4025               remainder_size = size - nb;
4026
4027               /* unlink */
4028               unlink (av, victim, bck, fwd);
4029
4030               /* Exhaust */
4031               if (remainder_size < MINSIZE)
4032                 {
4033                   set_inuse_bit_at_offset (victim, size);
4034                   if (av != &main_arena)
4035         set_non_main_arena (victim);
4036                 }
4037
4038               /* Split */
4039               else
4040                 {
4041                   remainder = chunk_at_offset (victim, nb);
4042
4043                   /* We cannot assume the unsorted list is empty and therefore
4044                      have to perform a complete insert here.  */
4045                   bck = unsorted_chunks (av);
4046                   fwd = bck->fd;
4047       if (__glibc_unlikely (fwd->bk != bck))
4048         malloc_printerr ("malloc(): corrupted unsorted chunks 2");
4049                   remainder->bk = bck;
4050                   remainder->fd = fwd;
4051                   bck->fd = remainder;
4052                   fwd->bk = remainder;
4053
4054                   /* advertise as last remainder */
4055                   if (in_smallbin_range (nb))
4056                     av->last_remainder = remainder;
4057                   if (!in_smallbin_range (remainder_size))
4058                     {
4059                       remainder->fd_nextsize = NULL;
4060                       remainder->bk_nextsize = NULL;
4061                     }
4062                   set_head (victim, nb | PREV_INUSE |
4063                             (av != &main_arena ? NON_MAIN_ARENA : 0));
4064                   set_head (remainder, remainder_size | PREV_INUSE);
4065                   set_foot (remainder, remainder_size);
4066                 }
4067               check_malloced_chunk (av, victim, nb);
4068               void *p = chunk2mem (victim);
4069               alloc_perturb (p, bytes);
4070               return p;
4071             }
4072         }
4073

2 つのチャンクに分割( Split )します。

そして残りのチャンクは未整理ビン( Unsorted Bin )に挿入します。

4074     use_top:
4075       /*
4076          If large enough, split off the chunk bordering the end of memory
4077          (held in av->top). Note that this is in accord with the best-fit
4078          search rule.  In effect, av->top is treated as larger (and thus
4079          less well fitting) than any other available chunk since it can
4080          be extended to be as large as necessary (up to system
4081          limitations).
4082
4083          We require that av->top always exists (i.e., has size >=
4084          MINSIZE) after initialization, so if it would otherwise be
4085          exhausted by current request, it is replenished. (The main
4086          reason for ensuring it exists is that we may need MINSIZE space
4087          to put in fenceposts in sysmalloc.)
4088        */
4089
4090       victim = av->top;

victim は av→top を指します。

4091       size = chunksize (victim);
4092
4093       if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE))
4094         {
4095           remainder_size = size - nb;
4096           remainder = chunk_at_offset (victim, nb);
4097           av->top = remainder;
4098           set_head (victim, nb | PREV_INUSE |
4099                     (av != &main_arena ? NON_MAIN_ARENA : 0));
4100           set_head (remainder, remainder_size | PREV_INUSE);
4101
4102           check_malloced_chunk (av, victim, nb);
4103           void *p = chunk2mem (victim);
4104           alloc_perturb (p, bytes);
4105           return p;
4106         }

victim チャンクのサイズがリクエストサイズ + MINSIZE 以上ならば 2 つのチャンクに分割( Split )する。

片方は p として返し、残りのチャンクは新たなトップチャンクになります。

空のビンが見つからないなら、トップチャンク( Top Chunk )を使ってリクエストを処理してますね。

4107
4108       /* When we are using atomic ops to free fast chunks we can get
4109          here for all block sizes.  */
4110       else if (atomic_load_relaxed (&av->have_fastchunks))
4111         {
4112           malloc_consolidate (av);
4113           /* restore original bin index */
4114           if (in_smallbin_range (nb))
4115             idx = smallbin_index (nb);
4116           else
4117             idx = largebin_index (nb);
4118         }

アリーナ av にファーストチャンクがあるかチェックします。

ある場合は malloc_consolidate(av) コールしてからループに戻ります。

4119
4120       /*
4121          Otherwise, relay to handle system-dependent cases
4122        */
4123       else
4124         {
4125           void *p = sysmalloc (nb, av);
4126           if (p != NULL)
4127             alloc_perturb (p, bytes);
4128           return p;
4129         }
4130     }
4131 }

チャンクの分割や malloc_consolidate をしない場合は、sysmalloc() をコールしてメモリー領域を割り当てます。

Copyright 2018-2019, by Masaki Komatsu