目录
一、步骤1-标记MMAP分配的使用munmap_chunk释放
二、步骤2-释放的是小块内存,则chunk放入fastbin
三、步骤3-如果不是MMAP分配,则释放到unsorted bins
四、步骤4-如果nextchunk 就是Top chunk,则直接扩容Top chunk
五、步骤5-如果释放的内存比较大,则需要对chunk进行一些缩容处理
1. malloc_consolidate整理fastbin
2. 主分配区systrim缩容Top chunk
3. 非主分配区heap_trim缩容heap区域
六、步骤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
一、步骤1-标记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
}
二、步骤2-释放的是小块内存,则chunk放入fastbin
这里面有几个关键步骤:
- 首选,需要判断释放的内存小于get_max_fast()
- 通过free_perturb对当前内存块进行清空操作,并通过函数atomic_store_relaxed原子操作设置fastbin的空闲/繁忙状态标记
- 通过fastbin_index找到数组下标,fastbin函数找到对应的切入点可操作的chunk
- 如果是单线程则直接调整单向链表
- 如果是多线程,则通过catomic_compare_and_exchange_val_rel函数,原子操作fastbin链表
/**
* 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)");
}
三、步骤3-如果不是MMAP分配,则释放到unsorted bins
如果不是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);
四、步骤4-如果nextchunk 就是Top chunk,则直接扩容Top chunk
接着上一个步骤,如果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);
}
五、步骤5-如果释放的内存比较大,则需要对chunk进行一些缩容处理
如果释放的内存比较大,则需要对chunk进行一些缩容处理:
- 释放的内存size需要大于FASTBIN_CONSOLIDATION_THRESHOLD(64k),则尝试一次缩容的操作,缩容大小mp_.top_pad(128k)
- 如果fastbin中有数据,则调用malloc_consolidate进行整理,将fastbin上的数据进行合并整理到unsorted bin上。
-
如果是主分配区,如果是主分配区,并且主分配区的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);
}
1. malloc_consolidate整理fastbin
对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);
}
2. 主分配区systrim缩容Top chunk
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;
}
3. 非主分配区heap_trim缩容heap区域
我们知道,非主分配区主要通过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;
}
六、步骤6-MMAP方式分配的,则直接执行munmap_chunk
/*
If the chunk was allocated via mmap, release via munmap().
*/
/* 步骤6:MMAP方式分配的,则直接执行munmap_chunk */
else {
munmap_chunk (p);
}
}