目录
前面三章,我们讲解了malloc的核心分配函数_int_malloc。_int_malloc核心是从我们管理的bins上去寻找空闲的chunk,并分配内存。如果没有空闲的内存,则到Top chunk上去分配。如果Top chunk也无法满足分配的场景,则需要调用sysmalloc进行内存的分配。
本章节,我们重点讲sysmalloc的具体实现。
sysmalloc定义:当Top chunk内存空间不足的时候,就会调用sysmalloc函数进行内存分配操作。
参数:入参nb,为需要分配的;av为分配区状态机对象
- /*
- sysmalloc handles malloc cases requiring more memory from the system.
- On entry, it is assumed that av->top does not have enough
- space to service request for nb bytes, thus requiring that av->top
- be extended or replaced.
- 调用系统分配函数:sysmalloc
- 说明:进入sysmalloc则表示 top chunk的空间不足了,需要进行扩容av->top
- nb:请求的内存大小
- mstate:内存分配状态机(分配区)
- */
-
- static void *
- sysmalloc (INTERNAL_SIZE_T nb, mstate av)
- {
- mchunkptr old_top; /* 老的Topchunk的地址指针 mstate->top incoming value of av->top */
- INTERNAL_SIZE_T old_size; /* 老的Top chunk的大小 its size */
- char *old_end; /* 老的Top chunk的尾部地址 its end address */
-
- long size; /* 第一次分配的内存size arg to first MORECORE or mmap call */
- char *brk; /* 通过brk分配后返回的对象 return value from MORECORE */
-
- long correction; /* 用于记录第二次分配的值 arg to 2nd MORECORE call */
- char *snd_brk; /* 第二次处理后返回的值(也是第一次的尾部) 2nd return val */
-
- INTERNAL_SIZE_T front_misalign; /* 不可用的新空间的头部字节 unusable bytes at front of new space */
- INTERNAL_SIZE_T end_misalign; /* 新内存块尾部对齐的字节 partial page left at end of new space */
- char *aligned_brk; /* 对齐后的brk值 aligned offset into brk */
-
- mchunkptr p; /* 返回的结果p the allocated/returned chunk */
- mchunkptr remainder; /* Top chunk切割后剩余的remainder chunk remainder from allocation */
- unsigned long remainder_size; /* Top chunk切割后剩余的remainder chunk 的size its size */
-
-
- size_t pagesize = GLRO (dl_pagesize);
- bool tried_mmap = false;
sysmalloc基本逻辑:
try_mmap是尝试直接进行mmap的方式分配一段内存。当非主分配区通过扩容heap或者new heap都失败的情况下,采用try_mmap方式分配。
但是需要符合MMAP的阀值以及系统支持MMAP,nb分配的内存为大对象(超过128k)。该场景则直接返回MMAP分配的内存chunk,不调整Top chunk。
如果MMAP方式分配成功,对分配的内存进行对齐操作,需要计算偏移量,并标记该内存是IS_MMAPPED类型的。最后直接返回内存地址。
- /*
- If have mmap, and the request size meets the mmap threshold, and
- the system supports mmap, and there are few enough currently
- allocated mmapped regions, try to directly map this request
- rather than expanding top.
- 1. av==NULL,则直接采用MMAP的方式分配内存
- 2. nb分配的内存为大对象(超过128k),并且符合MMAP的阀值以及系统支持MMAP,则采用MMAP分配
- mp_.n_mmaps_max=65536
- mp_.mmap_threshold=128*1024
- 需要goto try_mmap,才会进入MMAP分配逻辑,该场景则直接返回MMAP分配的内存chunk,不调整Top chunk
- */
-
- if (av == NULL
- || ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold)
- && (mp_.n_mmaps < mp_.n_mmaps_max)))
- {
- char *mm; /* MMAP的返回值 return value from mmap call*/
-
- /* 尝试进行MMAP分配 */
- try_mmap:
- /*
- Round up size to nearest page. For mmapped chunks, the overhead
- is one SIZE_SZ unit larger than for normal chunks, because there
- is no following chunk whose prev_size field could be used.
- See the front_misalign handling below, for glibc there is no
- need for further alignments unless we have have high alignment.
- */
- /* 进行size的内存对齐操作 */
- if (MALLOC_ALIGNMENT == 2 * SIZE_SZ)
- size = ALIGN_UP (nb + SIZE_SZ, pagesize); //调整size
- else
- size = ALIGN_UP (nb + SIZE_SZ + MALLOC_ALIGN_MASK, pagesize);//调整size
- tried_mmap = true;
-
- /* Don't try if size wraps around 0 */
- if ((unsigned long) (size) > (unsigned long) (nb))
- {
- /* 直接调用MMAP映射一块内存,大小为size,可读可写*/
- mm = (char *) (MMAP (0, size, PROT_READ | PROT_WRITE, 0)); //调用MMAP的方式,获取一块size大小的内存
-
- /* 如果分配成功 */
- if (mm != MAP_FAILED)
- {
- /*
- The offset to the start of the mmapped region is stored
- in the prev_size field of the chunk. This allows us to adjust
- returned start address to meet alignment requirements here
- and in memalign(), and still be able to compute proper
- address argument for later munmap in free() and realloc().
- */
-
- /* 分配的mm内存地址需要进行内存对齐,front_misalign表示对齐的地址前有多少个可以对齐的字节*/
- if (MALLOC_ALIGNMENT == 2 * SIZE_SZ)
- {
- /* For glibc, chunk2mem increases the address by 2*SIZE_SZ and
- MALLOC_ALIGN_MASK is 2*SIZE_SZ-1. Each mmap'ed area is page
- aligned and therefore definitely MALLOC_ALIGN_MASK-aligned. */
- assert (((INTERNAL_SIZE_T) chunk2mem (mm) & MALLOC_ALIGN_MASK) == 0);
- front_misalign = 0;
- }
- else
- front_misalign = (INTERNAL_SIZE_T) chunk2mem (mm) & MALLOC_ALIGN_MASK;
-
- /* 如果有可以对齐的字节 */
- if (front_misalign > 0)
- {
-
- correction = MALLOC_ALIGNMENT - front_misalign; //计算偏移量
- p = (mchunkptr) (mm + correction); //mm+偏移量后,得到最终返回的chunk的地址
- //说白了对齐后,将便宜部分的字节当成了一个新的chunk结构,free的时候要一起清理
- set_prev_size (p, correction); //设置前一个p->mchunk_prev_size;
- set_head (p, (size - correction) | IS_MMAPPED); //设置p->mchunk_size,并且需要减去偏移量 (size + MMAP映射)
- }
- else
- {
- /* 这里不需要对齐操作*/
- p = (mchunkptr) mm; //获取得到chunk的指针地址
- set_prev_size (p, 0); //这里没有偏移,所以设置前一个mchunk_prev_size为0
- set_head (p, size | IS_MMAPPED); //设置p->mchunk_size (size + MMAP映射)
- }
-
- /* update statistics 更新各种状态*/
-
- int new = atomic_exchange_and_add (&mp_.n_mmaps, 1) + 1;
- atomic_max (&mp_.max_n_mmaps, new);
-
- unsigned long sum;
- sum = atomic_exchange_and_add (&mp_.mmapped_mem, size) + size;
- atomic_max (&mp_.max_mmapped_mem, sum);
-
- check_chunk (av, p);
-
- return chunk2mem (p); //这里返回内存地址,非chunk地址
- }
- }
- }
如果是非主分配区,则通过heap_info方式获取堆信息结构,并且通过MMAP分配内存。
brk和snd_brk默认值都设置为失败。brk为第一次分配后的指针地址;snd_brk为第二次分配的地址,同时也是第一次分配内存的尾部地址。
- /* There are no usable arenas and mmap also failed. */
- /* 如果分配区为空,则不能分配,返回 */
- if (av == NULL)
- return 0;
-
- /* Record incoming configuration of top */
- /* 获取top 的 顶部信息*/
- old_top = av->top; //老的Topchunk的地址
- old_size = chunksize (old_top); //老的Topchunk的size
- old_end = (char *) (chunk_at_offset (old_top, old_size)); //老的Topchunk的尾部地址
-
- /* brk=第一次分配返回值 ;snd_brk=第二次分配返回值 */
- brk = snd_brk = (char *) (MORECORE_FAILURE); //默认设置分配失败
如果剩余的空间不足,首先通过grow_heap尝试heap区的扩容。
grow_heap函数进行扩容,有分配页大小的限制,分配页的大小要小于HEAP_MAX_SIZE。
- /* 如果不是主分配区,则通过heap_info方式获取堆信息结构,并且通过MMAP分配内存 */
- if (av != &main_arena)
- {
- heap_info *old_heap, *heap;
- size_t old_heap_size;
-
- /* First try to extend the current heap. */
- /* 通过heap_for_ptr,获取当前的heap的数据结构 */
- old_heap = heap_for_ptr (old_top);
- old_heap_size = old_heap->size;
-
-
- /**
- * 如果剩余的空间不足,首先通过grow_heap尝试heap区的扩容
- * grow_heap函数进行扩容,有分配页大小的限制,分配页的大小要小于HEAP_MAX_SIZE
- */
- if ((long) (MINSIZE + nb - old_size) > 0
- && grow_heap (old_heap, MINSIZE + nb - old_size) == 0)
- {
- /* 扩容方式成功 */
- av->system_mem += old_heap->size - old_heap_size; //变更系统内存记录,增加部分为新的heap的size减去老的heap的值
- set_head (old_top, (((char *) old_heap + old_heap->size) - (char *) old_top)
- | PREV_INUSE); //设置p->mchunk_size (size + 使用中)
- }
扩容失败,则new一个新的heap ,并将av->top指向到新的heap
new_heap 通过MMAP方式分配一块内存, 32位系统每次映射1M,64位系统每次映射64M。
- /* 扩容失败,则new一个新的heap ;并将av->top指向到新的heap */
- /* new_heap 通过MMAP方式分配一块内存, 32位系统每次映射1M,64位系统每次映射64M*/
- else if ((heap = new_heap (nb + (MINSIZE + sizeof (*heap)), mp_.top_pad)))
- {
- /* Use a newly allocated heap. */
- heap->ar_ptr = av; //新的heap指向av
- heap->prev = old_heap; //指向前一个老的heap
- av->system_mem += heap->size; //调整分配区的系统内存
- /* Set up the new top. */
- /* #define top(ar_ptr) ((ar_ptr)->top) */
- top (av) = chunk_at_offset (heap, sizeof (*heap)); //减去heap结构的长度,就能定位到chunk的偏移量,并将new_heap出来的块放置到av->top上
- set_head (top (av), (heap->size - sizeof (*heap)) | PREV_INUSE); //设置p->mchunk_size
-
- /* Setup fencepost and free the old top chunk with a multiple of
- MALLOC_ALIGNMENT in size. */
- /* The fencepost takes at least MINSIZE bytes, because it might
- become the top chunk again later. Note that a footer is set
- up, too, although the chunk is marked in use. */
- old_size = (old_size - MINSIZE) & ~MALLOC_ALIGN_MASK;
- set_head (chunk_at_offset (old_top, old_size + 2 * SIZE_SZ), 0 | PREV_INUSE);//设置p->mchunk_size (size + PREV使用中)
- if (old_size >= MINSIZE)
- {
- set_head (chunk_at_offset (old_top, old_size), (2 * SIZE_SZ) | PREV_INUSE);//设置p->mchunk_size (size + PREV使用中)
- set_foot (chunk_at_offset (old_top, old_size), (2 * SIZE_SZ)); //设置p->mchunk_prev_size
- set_head (old_top, old_size | PREV_INUSE | NON_MAIN_ARENA);//设置p->mchunk_size (size + PREV使用中 + 非主分配区)
- _int_free (av, old_top, 1); //释放old_top
- }
- else
- {
- set_head (old_top, (old_size + 2 * SIZE_SZ) | PREV_INUSE);//设置p->mchunk_size (size + PREV使用中)
- set_foot (old_top, (old_size + 2 * SIZE_SZ));//设置p->mchunk_prev_size
- }
- }
- /* 直接跳转到try_mmap,通过MMAP分配一块内存 */
- else if (!tried_mmap)
- /* We can at least try to use to mmap memory. */
- goto try_mmap;
- }
如果是主分配区,则直接扩容Top chunk(brk和mmap方式都有)。
size 需要等于 nb(此次分配的容量) + top_pad(每次分配扩展值128K) + MINSIZE对齐字节
如果主分配区都是通过brk方式分配的,是连续性分配的,可以减去老的Top chunk剩余的old_size值。因为nb大于old_size。size也需要按照pagesize进行页对齐。
- else /* av == main_arena 如果是主分配区,则直接扩容Top chunk(brk和mmap方式都有)*/
-
-
- { /* Request enough space for nb + pad + overhead */
- //# define DEFAULT_TOP_PAD 131072 = 128*1024 mp_.top_pad默认值128K
- //mp_.top_pad 初始化或扩展堆的时候需要多申请的内存大小
- size = nb + mp_.top_pad + MINSIZE; //size=分配的内存需要加上 对齐的一些字节;
-
- /*
- If contiguous, we can subtract out existing space that we hope to
- combine with new space. We add it back later only if
- we don't actually get contiguous space.
- contiguous:用于判断是否为连续brk分配,主分配区先减去已经存在的top空间,再向操作系统申请
- 如果是连续brk分配,可以减去原有的old_size
- 如果是非连续brk分配,后续还会降old_size加回去
- 由于old_size小于nb,top_pad又是128K,所以减去之后也有足够的空间存储
- */
- if (contiguous (av))
- size -= old_size;
-
- /*
- Round to a multiple of page size.
- If MORECORE is not contiguous, this ensures that we only call it
- with whole-page arguments. And if MORECORE is contiguous and
- this is not first time through, this preserves page-alignment of
- previous calls. Otherwise, we correct to page-align below.
- */
- //按照页进行对齐 对齐
- size = ALIGN_UP (size, pagesize);
调用MORECORE进行brk的分配。
- //size大于0,然后通过系统调用(sbrk)分配size大小的内存
- if (size > 0)
- {
- brk = (char *) (MORECORE (size));
- LIBC_PROBE (memory_sbrk_more, 2, brk, size);
- }
-
- /* 如果分配成功 */
- if (brk != (char *) (MORECORE_FAILURE))
- {
- /* Call the `morecore' hook if necessary. */
- //分配成功,进行原子操作,调用__after_morecore_hook
- void (*hook) (void) = atomic_forced_read (__after_morecore_hook);
- if (__builtin_expect (hook != NULL, 0))
- (*hook)();
- }
进入mmap之后,相当于之前的brk被打断了,则此次size需要加上old_size值。
并通过MMAP方式分配一个size大小的内存块。
通过set_noncontiguous函数,设置当前分配区的brk分配已经不连续了。
- /* Cannot merge with old top, so add its size back in */
- /* 如果是连续的brk分配(主分配区才存在) */
- if (contiguous (av))
- size = ALIGN_UP (size + old_size, pagesize); //调整size大小,分配失败之后又把oldsize给加回去了
-
- /* If we are relying on mmap as backup, then use larger units */
- /* brk分配失败后,使用MMAP方式作为备用方案;如果size小于1M,则使用MMAP的默认值1M */
- if ((unsigned long) (size) < (unsigned long) (MMAP_AS_MORECORE_SIZE))
- size = MMAP_AS_MORECORE_SIZE; //MMAP_AS_MORECORE_SIZ = 1024 * 1024 = 1M
-
- /* Don't try if size wraps around 0 */
- if ((unsigned long) (size) > (unsigned long) (nb))
- {
- /* 这里使用MMAP分配1M的内存块;mbrk为MMAP分配后返回的对象 */
- char *mbrk = (char *) (MMAP (0, size, PROT_READ | PROT_WRITE, 0));
-
- /* 如果分配成功,则处理一下 */
- if (mbrk != MAP_FAILED)
- {
- /* We do not need, and cannot use, another sbrk call to find end */
- brk = mbrk; //调整brk的值
- snd_brk = brk + size; //这里设置到尾部值
-
- /*
- Record that we no longer have a contiguous sbrk region.
- After the first time mmap is used as backup, we do not
- ever rely on contiguous space since this could incorrectly
- bridge regions.
- */
- set_noncontiguous (av);//主分配区设置不连续的标记,因为这里使用了MMAP分配
- }
- }
- }
主分配区分配成功后,返回brk值为分配的内存地址。
后续如果是brk连续分配地址是相邻的,则直接扩容Top
如果非相邻的,则需要将老的Top chunk剩余的空间释放到bins上,并且经过一定裁剪和对齐之后,返回新的Top chunk。
- /* 分配成功的情况处理 */
- if (brk != (char *) (MORECORE_FAILURE))
- {
- if (mp_.sbrk_base == 0)
- mp_.sbrk_base = brk;
- av->system_mem += size; //调整av的系统内存大小
-
- /*
- If MORECORE extends previous space, we can likewise extend top size.
- */
-
- //判断是否是通过brk分配的用brk分配的,并且地址是连续的,则直接更新Top chunk即可(就是Top chunk的扩容)
- if (brk == old_end && snd_brk == (char *) (MORECORE_FAILURE))
- set_head (old_top, (size + old_size) | PREV_INUSE); //设置p->mchunk_size (size + PREV使用中)
新分配的内存地址大于原来的top chunk的结束地址,说明地址是不连续的,使用MMAP分配的,则无法直接扩容Top chunk。
有连续标记,说明是brk方式分配的。这里需要将老的Top的空间以及字节对齐的一些冗余空间进行brk二次扩容,放到第一次扩容的尾部。
最终我们要返回两个值:aligned_brk(对齐后的值)和snd_brk(二次扩容的值)
这里要重点说一下:内存地址对齐的目标是让内存分配更加合理和高效,例如chunk指针地址1001,通过对齐后是1024为启始地址。如果跟老的Top不相邻,则需要将老的Top剩余的Size + 内存地址对齐产生的前置内存碎片 重新扩容到新的Top尾部。老的Top剩余的chunk则需要free。
- //新分配的内存地址大于原来的top chunk的结束地址,说明地址是不连续的,使用MMAP分配的,则无法直接扩容Top chunk
- else
- {
- front_misalign = 0;
- end_misalign = 0;
- correction = 0;
- aligned_brk = brk;
-
- /* handle contiguous cases 有连续标记,说明是brk方式分配的 */
- if (contiguous (av))
- {
- /* Count foreign sbrk as system_mem. */
- if (old_size)
- av->system_mem += brk - old_end; //Topchunk不连续,需要记录外部不连续内存的大小
-
- /* 分配的mm内存地址需要进行内存对齐,front_misalign表示对齐的地址前有多少个可以对齐的字节*/
- front_misalign = (INTERNAL_SIZE_T) chunk2mem (brk) & MALLOC_ALIGN_MASK;
- if (front_misalign > 0) //如果大于0,说明可以计算这个偏移量,调整对齐后的aligned_brk地址
- {
- /*
- Skip over some bytes to arrive at an aligned position.
- We don't need to specially mark these wasted front bytes.
- They will never be accessed anyway because
- prev_inuse of av->top (and any chunk created from its start)
- is always true after initialization.
- 跳过一些字节达到对齐的位置。我们不需要特别标记这些浪费的前字节。
- */
-
- correction = MALLOC_ALIGNMENT - front_misalign; //对齐可调整的字节
- aligned_brk += correction; //aligned_brk往后调整几个字节地址,调整后的brk地址
- }
-
- /*
- If this isn't adjacent to existing space, then we will not
- be able to merge with old_top space, so must add to 2nd request.
- */
- //correction=新扩展出来的chunk需要继续扩容的大小 包含brk对齐后头部减少的字节 + 老的top的size
- correction += old_size;
-
- /* Extend the end address to hit a page boundary */
- end_misalign = (INTERNAL_SIZE_T) (brk + size + correction); //对齐后的新的top chunk的尾部地址
- correction += (ALIGN_UP (end_misalign, pagesize)) - end_misalign; //尾部地址需要进行一次对齐,对齐后是否需要增加字节
-
- //所以:correction=brk前置的对齐字节 + 老的top的size + 新的brk尾部的对齐字节
- //aligned_brk:为调整后的新的chunk的起始地址
- //snd_brk:2次扩容操作的返回值
-
- assert (correction >= 0);
- snd_brk = (char *) (MORECORE (correction)); //进行2次扩容操作,snd_brk为第二次扩容操作,扩容的值:correction
-
- /*
- If can't allocate correction, try to at least find out current
- brk. It might be enough to proceed without failing.
- Note that if second sbrk did NOT fail, we assume that space
- is contiguous with first sbrk. This is a safe assumption unless
- program is multithreaded but doesn't use locks and a foreign sbrk
- occurred between our first and second calls.
- */
-
- if (snd_brk == (char *) (MORECORE_FAILURE)) //扩容失败
- {
- correction = 0;
- snd_brk = (char *) (MORECORE (0)); //这里又变成尾部值
- }
- else
- {
- /* Call the `morecore' hook if necessary. */
- void (*hook) (void) = atomic_forced_read (__after_morecore_hook); //扩容成功
- if (__builtin_expect (hook != NULL, 0))
- (*hook)();
- }
- }
这里主要调整字节对齐和偏移量。mmap方式不进行二次扩容。
最终我们要返回两个值:aligned_brk(对齐后的值)和snd_brk(不扩容则直接尾部)
- /* handle non-contiguous cases 没有连续标记的Case,使用MMAP分配的情况 */
- else
- {
- if (MALLOC_ALIGNMENT == 2 * SIZE_SZ)
- /* MORECORE/mmap must correctly align */
- assert (((unsigned long) chunk2mem (brk) & MALLOC_ALIGN_MASK) == 0);
- else
- {
- front_misalign = (INTERNAL_SIZE_T) chunk2mem (brk) & MALLOC_ALIGN_MASK;
- if (front_misalign > 0)
- {
- /*
- Skip over some bytes to arrive at an aligned position.
- We don't need to specially mark these wasted front bytes.
- They will never be accessed anyway because
- prev_inuse of av->top (and any chunk created from its start)
- is always true after initialization.
- */
-
- aligned_brk += MALLOC_ALIGNMENT - front_misalign; //调整对齐,aligned_brk为调整后的起始地址
- }
- }
-
- /* Find out current end of memory */
- if (snd_brk == (char *) (MORECORE_FAILURE))
- {
- snd_brk = (char *) (MORECORE (0)); //尾部
- }
- }
1. 设置av->top指向调整后的aligned_brk
2. 将老的Top chunk上剩余的空间,释放到bins上
- /* Adjust top based on results of second sbrk 前面brk也好,MMAP也好都成功分配之后的操作*/
- if (snd_brk != (char *) (MORECORE_FAILURE))
- {
- av->top = (mchunkptr) aligned_brk; //将top指向调整过的aligned_brk地址
- set_head (av->top, (snd_brk - aligned_brk + correction) | PREV_INUSE); //设置p->mchunk_size (size + PREV使用中)
- av->system_mem += correction; //系统内存加上correction
-
- /*
- If not the first time through, we either have a
- gap due to foreign sbrk or a non-contiguous region. Insert a
- double fencepost at old_top to prevent consolidation with space
- we don't own. These fenceposts are artificial chunks that are
- marked as inuse and are in any case too small to use. We need
- two to make sizes and alignments work out.
- */
-
- /* 合并加工后的的old_top需要回收free */
- if (old_size != 0)
- {
- /*
- Shrink old_top to insert fenceposts, keeping size a
- multiple of MALLOC_ALIGNMENT. We know there is at least
- enough space in old_top to do this.
- 缩小2个字节,并重新设置old_top->mchunk_size,old_size是有足够空间缩小两个字节的
- */
- old_size = (old_size - 4 * SIZE_SZ) & ~MALLOC_ALIGN_MASK;
- set_head (old_top, old_size | PREV_INUSE);
-
- /*
- Note that the following assignments completely overwrite
- old_top when old_size was previously MINSIZE. This is
- intentional. We need the fencepost, even if old_top otherwise gets
- lost.
- */
- set_head (chunk_at_offset (old_top, old_size),
- (2 * SIZE_SZ) | PREV_INUSE); //设置
- set_head (chunk_at_offset (old_top, old_size + 2 * SIZE_SZ),
- (2 * SIZE_SZ) | PREV_INUSE);
-
- /* If possible, release the rest. */
- if (old_size >= MINSIZE)
- {
- _int_free (av, old_top, 1); //释放old_top的chunk
- }
- }
- }
如果Top chunk的大小大于分配的值(nb + MINISIZE),则进行切割分配操作,切割出来的分配出去,剩余的remainder变成Top chunk。
MINISIZE是最小的分配内存大小,在Top上分配至少留足一个MINISIZE的chunk,因为chunk的用户区域使用中的时候会复用下一个chunk的mchunk_prev_size字段的数据空间
- /* finally, do the allocation */
- p = av->top;
- size = chunksize (p); //获取Top chunk的size :p->mchunk_size
-
- /* check that one of the above allocation paths succeeded */
- /* 如果Top chunk的大小大于分配的值,则进行切割分配操作,切割出来的分配出去,剩余的remainder变成Top chunk*/
- if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE))
- {
- remainder_size = size - nb;
- remainder = chunk_at_offset (p, nb);
- av->top = remainder;
- set_head (p, nb | PREV_INUSE | (av != &main_arena ? NON_MAIN_ARENA : 0));
- set_head (remainder, remainder_size | PREV_INUSE);
- check_malloced_chunk (av, p, nb);
- return chunk2mem (p);
- }
至此,我们将malloc函数的实现基本讲解完了,下一章开始讲解free函数。