目录
一、步骤1-标记MMAP分配的使用munmap_chunk释放
二、步骤2-释放的是小块内存,则chunk放入fastbin
三、步骤3-如果不是MMAP分配,则释放到unsorted bins
四、步骤4-如果nextchunk 就是Top chunk,则直接扩容Top chunk
五、步骤5-如果释放的内存比较大,则需要对chunk进行一些缩容处理
1. malloc_consolidate整理fastbin
六、步骤6-MMAP方式分配的,则直接执行munmap_chunk
本章节主要讲解free函数的实现。free函数的入口函数:__libc_free,该入口函数也在malloc.c的文件中。
前几章节我们讲了malloc的具体实现,基本了解了ptmalloc是通过fast bins、unsorted bin、small bin、large bin 和 Top chunk等来管理释放后的内存的。free函数的基本步骤有6步:
步骤1:如果是MMAP分配的,则调用munmap_chunk进行chunk的释放操作
步骤2:如果释放的内存小于get_max_fast(),则释放的chunk放入fastbin
步骤3:如果不是MMAP分配,则释放的时候释放到unsorted bin
步骤四:如果释放的chunk的nextchunk 就是Top chunk,则直接扩容Top chunk
步骤五:如果释放的内存比较大,则需要对chunk进行一些缩容处理
步骤6:MMAP方式分配的,则直接执行munmap_chunk

如果是MMAP分配的,则调用munmap_chunk进行chunk的释放操作。
mchunk_size字段中的标记位IS_MMAPPED,如果是这个标记的说明是MMAP方式分配。
- /**
- * free()函数的入口
- */
- void
- __libc_free (void *mem)
- {
- mstate ar_ptr; //指针地址
- mchunkptr p; //chunk地址 /* chunk corresponding to mem */
-
- void (*hook) (void *, const void *)
- = atomic_forced_read (__free_hook);
- if (__builtin_expect (hook != NULL, 0))
- {
- (*hook)(mem, RETURN_ADDRESS (0));
- return;
- }
-
- /* 内存指针地址为0,则直接返回 */
- if (mem == 0) /* free(0) has no effect */
- return;
-
- p = mem2chunk (mem); //通过内存地址获取chunk地址
-
- /* 步骤1:如果是MMAP分配的,则调用munmap_chunk进行chunk的释放操作
- * 获取状态值,是否是MMAP分配的 mchunk_size字段中的标记位 IS_MMAPPED */
- if (chunk_is_mmapped (p)) /* release mmapped memory. */
- {
- /* See if the dynamic brk/mmap threshold needs adjusting.
- Dumped fake mmapped chunks do not affect the threshold. */
- if (!mp_.no_dyn_threshold
- && chunksize_nomask (p) > mp_.mmap_threshold
- && chunksize_nomask (p) <= DEFAULT_MMAP_THRESHOLD_MAX
- && !DUMPED_MAIN_ARENA_CHUNK (p))
- {
- mp_.mmap_threshold = chunksize (p);
- mp_.trim_threshold = 2 * mp_.mmap_threshold;
- LIBC_PROBE (memory_mallopt_free_dyn_thresholds, 2,
- mp_.mmap_threshold, mp_.trim_threshold);
- }
- munmap_chunk (p); //清空MMAP的chunk结构
- return;
- }
-
- MAYBE_INIT_TCACHE ();
-
- ar_ptr = arena_for_chunk (p); //获取分区地址
- _int_free (ar_ptr, p, 0); //调用free核心函数
- }
在malloc的时候,如果遇到try map方式实现MMAP方式的分配,都会有此标记。在通过Try mmap的方法中,会在分配chunk的时候进行对齐操作,并且对齐后因为前置会有空余字节,则会生成一个chunk,所以在释放free的时候也需要计算前一个chunk。
通过调用__munmap函数,最终来释放MMAP分配的内存。
- /**
- * MMAP 清除chunk数据
- */
- static void
- munmap_chunk (mchunkptr p)
- {
- size_t pagesize = GLRO (dl_pagesize);
- INTERNAL_SIZE_T size = chunksize (p); //获取chunk的size
-
- assert (chunk_is_mmapped (p));
-
- /* Do nothing if the chunk is a faked mmapped chunk in the dumped
- main arena. We never free this memory. */
- /* 如果是伪造的主分区的一个MMAP的chunk,则不做任何操作 */
- if (DUMPED_MAIN_ARENA_CHUNK (p))
- return;
-
- /* 在通过Try mmap的方法中,会在分配chunk的时候进行对齐操作,并且对齐后因为前置会有空余字节,则会生成一个chunk,free的时候要计算此chunk*/
- uintptr_t mem = (uintptr_t) chunk2mem (p); //获取内存地址
- uintptr_t block = (uintptr_t) p - prev_size (p); //指向前一个chunk的地址
- size_t total_size = prev_size (p) + size; //前一个空闲的大小
- /* Unfortunately we have to do the compilers job by hand here. Normally
- we would test BLOCK and TOTAL-SIZE separately for compliance with the
- page size. But gcc does not recognize the optimization possibility
- (in the moment at least) so we combine the two values into one before
- the bit test. */
- if (__glibc_unlikely ((block | total_size) & (pagesize - 1)) != 0
- || __glibc_unlikely (!powerof2 (mem & (pagesize - 1))))
- malloc_printerr ("munmap_chunk(): invalid pointer");
-
- atomic_decrement (&mp_.n_mmaps);
- atomic_add (&mp_.mmapped_mem, -total_size);
-
- /* If munmap failed the process virtual memory address space is in a
- bad shape. Just leave the block hanging around, the process will
- terminate shortly anyway since not much can be done. */
- __munmap ((char *) block, total_size); //释放MUNMAP,包含当前MMAP的chunk,以及对齐前置的chunk
- }
这里面有几个关键步骤:
- /**
- * free核心函数
- */
- static void
- _int_free (mstate av, mchunkptr p, int have_lock)
- {
- INTERNAL_SIZE_T size; /* its size */
- mfastbinptr *fb; /* associated fastbin */
- mchunkptr nextchunk; /* next contiguous chunk */
- INTERNAL_SIZE_T nextsize; /* its size */
- int nextinuse; /* true if nextchunk is used */
- INTERNAL_SIZE_T prevsize; /* size of previous contiguous chunk */
- mchunkptr bck; /* misc temp for linking */
- mchunkptr fwd; /* misc temp for linking */
-
- size = chunksize (p); //获取chunk的size
-
- .........
-
- /**
- * 步骤2:如果释放的内存小于get_max_fast(),则释放的chunk放入fastbin
- */
- if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())
-
- #if TRIM_FASTBINS
- /*
- If TRIM_FASTBINS set, don't place chunks
- bordering top into fastbins
- */
- && (chunk_at_offset(p, size) != av->top)
- #endif
- ) {
-
- if (__builtin_expect (chunksize_nomask (chunk_at_offset (p, size))
- <= 2 * SIZE_SZ, 0)
- || __builtin_expect (chunksize (chunk_at_offset (p, size))
- >= av->system_mem, 0))
- {
- bool fail = true;
- /* We might not have a lock at this point and concurrent modifications
- of system_mem might result in a false positive. Redo the test after
- getting the lock. */
- if (!have_lock)
- {
- __libc_lock_lock (av->mutex);
- fail = (chunksize_nomask (chunk_at_offset (p, size)) <= 2 * SIZE_SZ
- || chunksize (chunk_at_offset (p, size)) >= av->system_mem);
- __libc_lock_unlock (av->mutex);
- }
-
- if (fail)
- malloc_printerr ("free(): invalid next size (fast)");
- }
-
- /* 对当前内存块进行清空操作,设置的大小等于chunk的size 减去2个SIZE_SZ的空间 */
- free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
-
- atomic_store_relaxed (&av->have_fastchunks, true); //设置分配区的标志位表示fastbin有空闲chunk,原子操作
- unsigned int idx = fastbin_index(size); //获取fastbin 数组下标
- fb = &fastbin (av, idx); //找到对应的fb
-
- /* Atomically link P to its fastbin: P->FD = *FB; *FB = P; */
- mchunkptr old = *fb, old2;
-
- /* 如果是单线程处理,则直接操作 */
- if (SINGLE_THREAD_P)
- {
- /* Check that the top of the bin is not the record we are going to
- add (i.e., double free). */
- if (__builtin_expect (old == p, 0))
- malloc_printerr ("double free or corruption (fasttop)");
- p->fd = old;
- *fb = p;
- }
- else
- do
- {
- /* Check that the top of the bin is not the record we are going to
- add (i.e., double free). */
- /* 如果是多线程的,则需要进行原子操作 */
- if (__builtin_expect (old == p, 0))
- malloc_printerr ("double free or corruption (fasttop)");
- p->fd = old2 = old;
- }
- //catomic_compare_and_exchange_val_rel 原子操作 如果*MEM等于OLDVAL,则将*MEM存储为NEWVAL,返回OLDVAL
- while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2))
- != old2);
-
- /* Check that size of fastbin chunk at the top is the same as
- size of the chunk that we are adding. We can dereference OLD
- only if we have the lock, otherwise it might have already been
- allocated again. */
- if (have_lock && old != NULL
- && __builtin_expect (fastbin_index (chunksize (old)) != idx, 0))
- malloc_printerr ("invalid fastbin entry (free)");
- }
如果不是MMAP分配,则直接放入unsorted bins,未整理的bins上。那什么时候放入small bin或者large bin上呢,是在malloc分配的时候,会去循环遍历unsorted bin的双向链表上每一个未存储的chunk,并对未整理的chunk进行合并、整理操作。
如果不是MMAP分配,则释放的时候释放到unsorted bins。当malloc分配的时候,会去遍历unsorted bins,寻找合适的chunk。并对未整理的chunk进行合并、整理操作。
如果物理相邻的前一个chunk也是空闲状态,则合并前一个chunk。并通过unlink_chunk函数,解除前一个chunk在bins上的链表关系
如果物理相邻的后一个chunk不为Top chunk,则需要判断使用状态,如果也是空闲状态,则合并;如果是使用状态,则清除后一个chunk的PREV_INUSE状态
最后,通过unsorted_chunks函数,获取unsorted的bins对象,并将整理后的chunk放入到未整理的bins上
- /**
- * 步骤3:如果不是MMAP分配,则释放的时候释放到unsorted bins
- */
- else if (!chunk_is_mmapped(p)) {
-
- /* If we're single-threaded, don't lock the arena. */
- if (SINGLE_THREAD_P)
- have_lock = true;
-
- if (!have_lock)
- __libc_lock_lock (av->mutex);
-
- nextchunk = chunk_at_offset(p, size); //获取下一个chunk
-
- ............
- nextsize = chunksize(nextchunk); //下一个chunk的size
- if (__builtin_expect (chunksize_nomask (nextchunk) <= 2 * SIZE_SZ, 0)
- || __builtin_expect (nextsize >= av->system_mem, 0))
- malloc_printerr ("free(): invalid next size (normal)");
-
- /* 对当前内存块进行清空操作,设置的大小等于chunk的size 减去2个SIZE_SZ的空间 */
- free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
-
- /* consolidate backward */
- /* 如果前一个chunk也是空闲的,则要合并这个chunk */
- if (!prev_inuse(p)) {
- prevsize = prev_size (p); //获取前一个chunk的 size
- size += prevsize; //
- p = chunk_at_offset(p, -((long) prevsize)); //p值指向前一个chunk地址
- if (__glibc_unlikely (chunksize(p) != prevsize))
- malloc_printerr ("corrupted size vs. prev_size while consolidating");
- /* 解除这个chunk在bins上的关系,为何要解除呢?因为前面这个chunk是空闲的基本就挂载在bins上 */
- /* 这里的两个chunk是需要进行合并的 */
- unlink_chunk (av, p);
- }
-
- /* 如果nextchunk 不是 Topchunk */
- if (nextchunk != av->top) {
- /* get and clear inuse bit */
- nextinuse = inuse_bit_at_offset(nextchunk, nextsize); //获取下一个chunk的使用状态
-
- /* consolidate forward */
- if (!nextinuse) { //如果空闲的,则进行内存合并
- unlink_chunk (av, nextchunk); //解除下一个chunk
- size += nextsize; //内存合并,扩大内存size
- } else
- clear_inuse_bit_at_offset(nextchunk, 0); //如果非空闲,则清除nextchunk的PREV_INUSE状态
-
- /*
- Place the chunk in unsorted chunk list. Chunks are
- not placed into regular bins until after they have
- been given one chance to be used in malloc.
- */
-
- bck = unsorted_chunks(av); //获取unsorted bins的对象
- fwd = bck->fd;
- if (__glibc_unlikely (fwd->bk != bck))
- malloc_printerr ("free(): corrupted unsorted chunks");
- /* 放入链表中 */
- p->fd = fwd;
- p->bk = bck;
- /* 如果不为small bin,则设置fd_nextsize/bk_nextsize值*/
- if (!in_smallbin_range(size)) {
- p->fd_nextsize = NULL;
- p->bk_nextsize = NULL;
- }
- /* 调整前后bck和fwd的指向 */
- bck->fd = p;
- fwd->bk = p;
-
- set_head(p, size | PREV_INUSE); //设置头部
- set_foot(p, size); //设置脚部
-
- check_free_chunk(av, p);
接着上一个步骤,如果nextchunk就是Topchunk,意味着当前要释放的chunk跟Top chunk物理地址相邻,则释放的时候直接释放到Top chunk上即可(调整Top chunk的指针即可)
- /* 步骤4:如果nextchunk 就是Top chunk,则直接扩容Top chunk */
- } else {
- size += nextsize;
- set_head(p, size | PREV_INUSE);
- av->top = p;
- check_chunk(av, p);
- }
如果释放的内存比较大,则需要对chunk进行一些缩容处理:
如果是主分配区,如果是主分配区,并且主分配区的top chunk大于一定的值,就通过systrim缩小top chunk
如果是非主分配区,就获得top chunk对应的非主分配区的heap_info指针,调用heap_trim尝试缩小该heap
- /**
- * 步骤5:如果释放的内存比较大,则需要对chunk进行一些缩容处理
- * FASTBIN_CONSOLIDATION_THRESHOLD = 65536UL
- * mp_.top_pad = 128k = 131072
- * 1. size需要大于FASTBIN_CONSOLIDATION_THRESHOLD
- * 2. 如果fastbin中有数据,则调用malloc_consolidate进行整理
- * 3. 如果是主分配区,如果是主分配区,并且主分配区的top chunk大于一定的值,就通过systrim缩小top chunk
- * 4. 如果是非主分配区,就获得top chunk对应的非主分配区的heap_info指针,调用heap_trim尝试缩小该heap
- */
- if ((unsigned long)(size) >= FASTBIN_CONSOLIDATION_THRESHOLD) {
-
- /* 原子操作,获取是否fastbin中,有fastbin的chunk*/
- if (atomic_load_relaxed (&av->have_fastchunks))
- malloc_consolidate(av); //对fastbin进行整理合并操作,整理后的放入unsorted bin
-
- /* 主分配区操作:systrim缩小top chunk*/
- if (av == &main_arena) {
- #ifndef MORECORE_CANNOT_TRIM
- if ((unsigned long)(chunksize(av->top)) >=
- (unsigned long)(mp_.trim_threshold))
- systrim(mp_.top_pad, av);
- #endif
- /* 非主分配区操作:调用heap_trim尝试缩小该heap*/
- } else {
- /* Always try heap_trim(), even if the top chunk is not
- large, because the corresponding heap might go away. */
- heap_info *heap = heap_for_ptr(top(av));
-
- assert(heap->ar_ptr == av);
- heap_trim(heap, mp_.top_pad); //缩小
- }
- }
-
- if (!have_lock)
- __libc_lock_unlock (av->mutex);
- }
对fastbin进行整理合并操作,整理后的放入unsorted bin。
循环遍历fastbin,并检查物理相邻前一个chunk的使用状态,如果前一个chunk空闲中,则合并。
然后检查物理相邻的后一个chunk的使用状态,如果后一个chunk空闲中,则合并。如果后一个chunk就是Top chunk,则回收到Top chunk上去。如果后一个chunk不是Top chunk,则回收到unsorted bin上去。
- static void malloc_consolidate(mstate av)
- {
- mfastbinptr* fb; /* current fastbin being consolidated */
- mfastbinptr* maxfb; /* last fastbin (for loop control) */
- mchunkptr p; /* current chunk being consolidated */
- mchunkptr nextp; /* next chunk to consolidate */
- mchunkptr unsorted_bin; /* bin header */
- mchunkptr first_unsorted; /* chunk to link to */
-
- /* These have same use as in free() */
- mchunkptr nextchunk;
- INTERNAL_SIZE_T size;
- INTERNAL_SIZE_T nextsize;
- INTERNAL_SIZE_T prevsize;
- int nextinuse;
-
- atomic_store_relaxed (&av->have_fastchunks, false); //直接设置标记,没有fast chunk
-
- /* 获取unsorted bin */
- unsorted_bin = unsorted_chunks(av);
-
- /*
- Remove each chunk from fast bin and consolidate it, placing it
- then in unsorted bin. Among other reasons for doing this,
- placing in unsorted bin avoids needing to calculate actual bins
- until malloc is sure that chunks aren't immediately going to be
- reused anyway.
- */
-
- maxfb = &fastbin (av, NFASTBINS - 1); //获取最后一个fastbin
- fb = &fastbin (av, 0); //获取当前的fastbin
- do {
- p = atomic_exchange_acq (fb, NULL);
- if (p != 0) {
- do {
- {
- unsigned int idx = fastbin_index (chunksize (p));
- if ((&fastbin (av, idx)) != fb)
- malloc_printerr ("malloc_consolidate(): invalid chunk size");
- }
-
- check_inuse_chunk(av, p); //检查chunk的使用状态
- nextp = p->fd; //用于遍历整个fastbin的单向链表
-
- /* Slightly streamlined version of consolidation code in free() */
- size = chunksize (p); //chunk的size
- nextchunk = chunk_at_offset(p, size); //下一个chunk
- nextsize = chunksize(nextchunk); //下一个chunk的size
-
- /* 如果前一个chunk空闲,则将前一个物理相邻的chunk进行合并 */
- if (!prev_inuse(p)) {
- prevsize = prev_size (p);
- size += prevsize;
- p = chunk_at_offset(p, -((long) prevsize));
- if (__glibc_unlikely (chunksize(p) != prevsize))
- malloc_printerr ("corrupted size vs. prev_size in fastbins");
- unlink_chunk (av, p);
- }
-
- /* 如果nextchunk不是Top chunk*/
- if (nextchunk != av->top) {
- nextinuse = inuse_bit_at_offset(nextchunk, nextsize); //获取nextchunk的使用状态
-
- /* 如果空闲中 */
- if (!nextinuse) {
- size += nextsize; //调整size大小,合并nextchunk
- unlink_chunk (av, nextchunk);
- } else
- clear_inuse_bit_at_offset(nextchunk, 0); //如果非空闲,则清除nextchunk的PREV_INUSE状态
-
- /* 然后将chunk 放置到unsorted_bin 上去 */
- first_unsorted = unsorted_bin->fd;
- unsorted_bin->fd = p;
- first_unsorted->bk = p;
-
- if (!in_smallbin_range (size)) {
- p->fd_nextsize = NULL;
- p->bk_nextsize = NULL;
- }
-
- set_head(p, size | PREV_INUSE);
- p->bk = unsorted_bin;
- p->fd = first_unsorted;
- set_foot(p, size);
- }
- /* 如果是Top chunk,则将当前chunk或者合并过的chunk,都设置到Top chunk,调整Top chunk指针地址*/
- else {
- size += nextsize;
- set_head(p, size | PREV_INUSE);
- av->top = p;
- }
-
- } while ( (p = nextp) != 0);
-
- }
- } while (fb++ != maxfb);
- }
systrim函数主要用来缩容Top chunk。首先需要判断缩容的空间大小,如果缩容空间大小有限,则不进行缩容操作。缩容过程中,需要检查当前的指针地址是否跟 Topchunk的尾部地址是相等的,避免外部调用过sbrk 。MORECORE函数为brk函数的实现, MORECORE (-extra)即是缩容,指针往后推extra空间。通过老的Topchunk的尾部指针地址 减去 新的Topchunk的尾部指针地址,则是最终缩容的空间。
- static int
- systrim (size_t pad, mstate av)
- {
- long top_size; /* Amount of top-most memory */
- long extra; /* Amount to release */
- long released; /* Amount actually released */
- char *current_brk; /* address returned by pre-check sbrk call */
- char *new_brk; /* address returned by post-check sbrk call */
- size_t pagesize;
- long top_area;
-
- pagesize = GLRO (dl_pagesize);
- top_size = chunksize (av->top); //获取Topchunk size
-
- /* 如果没什么空间了,则返回不缩小 */
- top_area = top_size - MINSIZE - 1;
- if (top_area <= pad)
- return 0;
-
- /* Release in pagesize units and round down to the nearest page. */
- extra = ALIGN_DOWN(top_area - pad, pagesize); //经过对齐后的需要裁剪的量
-
- if (extra == 0)
- return 0;
-
- /*
- Only proceed if end of memory is where we last set it.
- This avoids problems if there were foreign sbrk calls.
- */
- /* 检查当前的指针地址是否跟 Topchunk的尾部地址是相等的,避免外部调用过sbrk*/
- current_brk = (char *) (MORECORE (0));
- if (current_brk == (char *) (av->top) + top_size)
- {
- /*
- Attempt to release memory. We ignore MORECORE return value,
- and instead call again to find out where new end of memory is.
- This avoids problems if first call releases less than we asked,
- of if failure somehow altered brk value. (We could still
- encounter problems if it altered brk in some very bad way,
- but the only thing we can do is adjust anyway, which will cause
- some downstream failure.)
- */
-
- MORECORE (-extra); //extra为要缩容的空间
- /* Call the `morecore' hook if necessary. */
- void (*hook) (void) = atomic_forced_read (__after_morecore_hook);
- if (__builtin_expect (hook != NULL, 0))
- (*hook)();
- new_brk = (char *) (MORECORE (0)); //为新的Topchunk的尾部地址
-
- LIBC_PROBE (memory_sbrk_less, 2, new_brk, extra);
-
- if (new_brk != (char *) MORECORE_FAILURE)
- {
- released = (long) (current_brk - new_brk); //计算释放的虚拟内存的大小
-
- if (released != 0)
- {
- /* Success. Adjust top. */
- av->system_mem -= released; //减去系统内存空间
- set_head (av->top, (top_size - released) | PREV_INUSE); //设置状态
- check_malloc_state (av);
- return 1;
- }
- }
- }
- return 0;
- }
我们知道,非主分配区主要通过MMAP的方式每次分配一块大对象用来当Top chunk。多次分配的时候通过heap结构的链表来进行链接管理。《ptmalloc源码分析 - 分配区heap_info结构实现(05)》 在第五章节中我们详细讲解过heap_info结构,这里不展开。
heap_trim函数主要是通过计算得到需要缩容的空间,最终调用shrink_heap函数来实现缩容。
- /* 用来缩小非主分配区的heap大小 */
- static int heap_trim(heap_info *heap, size_t pad) {
- mstate ar_ptr = heap->ar_ptr;
- unsigned long pagesz = GLRO(dl_pagesize);
- mchunkptr top_chunk = top(ar_ptr), p;
- heap_info *prev_heap;
- long new_size, top_size, top_area, extra, prev_size, misalign;
-
- /* Can this heap go away completely? */
- while (top_chunk == chunk_at_offset(heap, sizeof(*heap))) {
- prev_heap = heap->prev;
- prev_size = prev_heap->size - (MINSIZE - 2 * SIZE_SZ);
- p = chunk_at_offset(prev_heap, prev_size);
- /* fencepost must be properly aligned. */
- misalign = ((long) p) & MALLOC_ALIGN_MASK;
- p = chunk_at_offset(prev_heap, prev_size - misalign);
- assert(chunksize_nomask(p) == (0 | PREV_INUSE)); /* must be fencepost */
- p = prev_chunk(p);
- new_size = chunksize(p) + (MINSIZE - 2 * SIZE_SZ) + misalign;
- assert(new_size > 0 && new_size < (long) (2 * MINSIZE));
- if (!prev_inuse(p))
- new_size += prev_size(p);
- assert(new_size > 0 && new_size < HEAP_MAX_SIZE);
- if (new_size + (HEAP_MAX_SIZE - prev_heap->size)
- < pad + MINSIZE + pagesz)
- break;
- ar_ptr->system_mem -= heap->size;
- LIBC_PROBE(memory_heap_free, 2, heap, heap->size);
- delete_heap(heap);
- heap = prev_heap;
- if (!prev_inuse(p)) /* consolidate backward */
- {
- p = prev_chunk(p);
- unlink_chunk(ar_ptr, p);
- }
- assert(((unsigned long) ((char *) p + new_size) & (pagesz - 1)) == 0);
- assert(((char *) p + new_size) == ((char *) heap + heap->size));
- top (ar_ptr) = top_chunk = p;
- set_head(top_chunk, new_size | PREV_INUSE);
- /*check_chunk(ar_ptr, top_chunk);*/
- }
-
- /* Uses similar logic for per-thread arenas as the main arena with systrim
- and _int_free by preserving the top pad and rounding down to the nearest
- page. */
- top_size = chunksize(top_chunk); //Top chunk的大小
- if ((unsigned long) (top_size) < (unsigned long) (mp_.trim_threshold))
- return 0;
-
- top_area = top_size - MINSIZE - 1; //Top chunk的区域
- if (top_area < 0 || (size_t) top_area <= pad)
- return 0;
-
- /* Release in pagesize units and round down to the nearest page. */
- extra = ALIGN_DOWN(top_area - pad, pagesz); //缩容的大小
- if (extra == 0)
- return 0;
-
- /* Try to shrink. 尝试调用缩小函数 */
- if (shrink_heap(heap, extra) != 0)
- return 0;
-
- ar_ptr->system_mem -= extra;
-
- /* Success. Adjust top accordingly. */
- set_head(top_chunk, (top_size - extra) | PREV_INUSE);
- /*check_chunk(ar_ptr, top_chunk);*/
- return 1;
- }
- /*
- If the chunk was allocated via mmap, release via munmap().
- */
- /* 步骤6:MMAP方式分配的,则直接执行munmap_chunk */
- else {
- munmap_chunk (p);
- }
- }