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 }
3564av が 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); \
3580REMOVE_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 #endifTCACHE についての説明は割愛します。
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);
3740victim のチャンクサイズが 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 #endifTCACHE は割愛です… (´・ω・`)
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 }
40732 つのチャンクに分割( 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