1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
| //如果unsorted bins不为空,从尾到头遍历unsorted bin中的每个chunk while ((victim = unsorted_chunks(av)->bk) != unsorted_chunks(av)) { //取出unsorted的尾部的chunk,此时victim即为尾部的chunk bck = victim->bk; /*, 检查当前遍历的 chunk 是否合法,chunk 的大小不能小于等于 2 * SIZE_SZ, 也不能超过 该分配区总的内存分配量。然后获取 chunk 的大小并赋值给 size。 这里的检查似乎有点小问题,直接使用了 victim->size,但 victim->size 中包含了相关的标志位信息,使用 chunksize(victim) 才比较合理,但在 unsorted bin 中的空闲 chunk 的所有标志位都清零了,所以这里直接 victim->size 没有问题。 */ if (__builtin_expect(victim->size <= 2 * SIZE_SZ, 0) || __builtin_expect(victim->size > av->system_mem, 0)) malloc_printerr(check_action, "malloc(): memory corruption", chunk2mem(victim), av);
size = chunksize(victim);//获取victim的size
/* 如果要申请的大小在smallbin范围 且 unsorted chunks 只有一个chunk,且 victim是last_remainder 且 victim的size大于请求的chunk的大小nb加上 (MINSIZE)最小chunk的size,那么就切割remainder,然后返回victim。 last_remainder 是一个 chunk 指针,分配区上次分配 small chunk 时, 从一个 chunk 中分 裂出一个 small chunk 返回给用户,分裂后的剩余部分 形成一个 chunk,last_remainder 就是 指向的这个 chunk。 */ if (in_smallbin_range(nb) && bck == unsorted_chunks(av) && victim == av->last_remainder && (unsigned long) (size) > (unsigned long) (nb + MINSIZE)) {
//分割remainder remainder_size = size - nb;//计算分割后剩下的size remainder = chunk_at_offset(victim, nb);//获取remainder的地址 //把remainder加入unsorted bin中 unsorted_chunks(av)->bk = unsorted_chunks(av)->fd = remainder; av->last_remainder = remainder; // 设置last_remainder为remainder remainder->bk = remainder->fd = unsorted_chunks(av); //如果是remainder在large bin的范围,则把fd_nextsize,fd_nextsize清零 if (!in_smallbin_range(remainder_size)) { remainder->fd_nextsize = NULL; remainder->fd_nextsize = NULL; } //设置victim的size set_head(victim, nb | PREV_INUSE | (av != &main_arena ? NON_MAIN_ARENA : 0)); //设置remainder的size set_head(remainder, remainder_size | PREV_INUSE); //设置remainder的物理相邻的下一个chunk的prev_size set_foot(remainder, remainder_size);
check_malloced_chunk(av, victim, nb);//默认不做任何操作 void *p = chunk2mem(victim);//将chunk指针转化为mem指针 alloc_perturb(p, bytes);//将p的mem部分全部设置为bytes ,默认什么也不做 return p; }
//把victim从unsorted bin 中移除 unsorted_chunks(av)->bk = bck; bck->fd = unsorted_chunks(av);
//如果 victim 的size 与申请的size相等,那么就返回其。 if (size == nb) { //设置victim物理相邻的下一个chunk的prev_inuse位 set_inuse_bit_at_offset(victim, size); //如果av不是main_arena 也就是说如果不是主进程,设置NON_MAIN_ARENA位 if (av != &main_arena) victim->size |= NON_MAIN_ARENA;
check_malloced_chunk(av, victim, nb); // 默认不做任何操作 void *p = chunk2mem(victim);//把chunk转换为mem指针 alloc_perturb(p, bytes);//将p的mem部分全部设置为bytes ,默认什么也不做 return p; }
//如果上一步取出的chunk没有匹配成功,那么将该chunk放入对应的bin中 //如果在smallbin的范围,则放到对应多small bin中 if (in_smallbin_range(size)) { victim_index = smallbin_index(size);//获取size对应的smallbin的index bck = bin_at(av, victim_index);//bck指向size对应的smallbin的链表头 //fwd指向size对应的smallbin的链表中的新加入的chunk(small bin使用头插法) fwd = bck->fd; } else//如果不再smallbin的范围,也就是说在large bin 的范围 { victim_index = largebin_index(size);//获取size对应的large bin的index bck = bin_at(av, victim_index);//bck指向size对应的large bin的链表头 fwd = bck->fd;//fwd指向size对应的large bin的链表中的新加入的chunk //如果large bin 非空,在largbin进行按顺序插入 if (fwd != bck) { /* Or with inuse bit to speed comparisons */ size |= PREV_INUSE; assert((bck->bk->size & NON_MAIN_ARENA) == 0);//默认不启用assert /* large bin中的chunk是按从大到小排列的,如果size < large bin 的最后一个chunk,说明size是这个large bin中的最小的,我们把它 加入到此large bin尾部。 */ if ((unsigned long) (size) < (unsigned long) (bck->bk->size)) { fwd = bck; bck = bck->bk; /* large bin 中size最小的chunk的fd_nextsize会指向size最大的 那个chunk,也就是首部的chunk。同样,large bin 中size最大的 chunk的bk_nextsize会指向size最小的那个chunk。 victim的bk_nextsize指向large bin原来最小的chunk,它的 bk_nextsize指向最大的那个chunk。那么原来的最小的就成了第二小的了。 把它fd_nextsize和bk_nextsize都修正。 */ victim->fd_nextsize = fwd->fd; victim->bk_nextsize = fwd->fd->bk_nextsize; //最大size的chunk的bk_nextsize,和原来最小chunk的bk_nextsize都指向victim fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim; } else //如果victim不是large bin 中最小的chunk { assert((fwd->size & NON_MAIN_ARENA) == 0);//默认不启用assert //从大到小(从头到尾)找到合适的位置 while ((unsigned long) size < fwd->size) { fwd = fwd->fd_nextsize; assert((fwd->size & NON_MAIN_ARENA) == 0); } //如果size刚好相等,就直接加入到其后面省的改fd_nextsize和bk_nextsize了 if ((unsigned long) size == (unsigned long) fwd->size) fwd = fwd->fd; else { //size不相等,即size>fwd->size,把victim加入到纵向链表中 victim->fd_nextsize = fwd; victim->bk_nextsize = fwd->bk_nextsize; fwd->bk_nextsize = victim; victim->bk_nextsize->fd_nextsize = victim; } bck = fwd->bk; } } else //如果large bin 为空,将victim加入到纵向列表 victim->fd_nextsize = victim->bk_nextsize = victim; }
//#define mark_bin(m, i) ((m)->binmap[idx2block (i)] |= idx2bit (i)) mark_bin(av, victim_index); //把victim加入到的bin的表示为非空 //把victim加入到对应的bin的链表中 victim->bk = bck; victim->fd = fwd; fwd->bk = victim; bck->fd = victim; } //可以发现当执行malloc操作时,从unsortedbin中寻找chunk时,如果没有大小相等的chunk,就会将unsorted斌中末尾chunk放入smallbin中或largebin中,再进行切割取出。
|