ptmalloc源码分析 - Top chunk的扩容函数sysmalloc实现(09)
目录
一、sysmalloc函数基本分配逻辑
二、强制try_mmap分配方式
三、非主分配区分配的实现
1. 设置老的Top chunk的参数
2. 尝试使用grow_heap函数
3. 尝试使用new_heap函数
4. 尝试使用try_mmap方式
四、主分配区分配的实现
1. 设置Top扩容的size值
2. brk分配成功的方式
3. brk分配失败采用MMAP分配
五、主分配区分配成功后对齐裁剪操作
1. 内存地址连续相邻直接扩容Top
2. brk方式分配地址不相邻情况
3. mmap方式分配地址不相邻情况
4. 设置调整后的Topchunk
六、切割新的Topchunk分配内存
前面三章,我们讲解了malloc的核心分配函数_int_malloc。_int_malloc核心是从我们管理的bins上去寻找空闲的chunk,并分配内存。如果没有空闲的内存,则到Top chunk上去分配。如果Top chunk也无法满足分配的场景,则需要调用sysmalloc进行内存的分配。
本章节,我们重点讲sysmalloc的具体实现。
一、sysmalloc函数基本分配逻辑
sysmalloc定义:当Top chunk内存空间不足的时候,就会调用sysmalloc函数进行内存分配操作。
参数:入参nb,为需要分配的;av为分配区状态机对象
sysmalloc基本逻辑:
- 非主分配区,通过MMAP并生成heap对象进行Top chunk的扩容操作。
- 非主分配区使用MMAP分配,32位操作系统每次分配1M,64位系统每次分配64M
- 非主分配区如果分配失败,则调用try_mmap,直接通过MMAP返回需要的内存
- 主分配区里面,一般情况下调用brk对Top chunk进行扩容
- 主分配区如果通过brk分配失败,则才调用MMAP方式分配
- 主分配区brk分配,每次除了需要分配的nb内存字节外,额外还会扩容mp_.top_pad=128K的内存空间;如果主分配区使用MMAP分配,每次分配1M+
- 无论主分配区还是非主分配区,分配成功后,都要对分配的内存进行一系列对齐、标记、裁剪、释放等操作
- 最后,切割当前需要分配的内存,并将Remainder chunk指向Top chunk地址
/*sysmalloc handles malloc cases requiring more memory from the system.On entry, it is assumed that av->top does not have enoughspace to service request for nb bytes, thus requiring that av->topbe extended or replaced.调用系统分配函数:sysmalloc说明:进入sysmalloc则表示 top chunk的空间不足了,需要进行扩容av->topnb:请求的内存大小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;
二、强制try_mmap分配方式
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, andthe system supports mmap, and there are few enough currentlyallocated mmapped regions, try to directly map this requestrather than expanding top.1. av==NULL,则直接采用MMAP的方式分配内存2. nb分配的内存为大对象(超过128k),并且符合MMAP的阀值以及系统支持MMAP,则采用MMAP分配mp_.n_mmaps_max=65536mp_.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 overheadis one SIZE_SZ unit larger than for normal chunks, because thereis no following chunk whose prev_size field could be used.See the front_misalign handling below, for glibc there is noneed for further alignments unless we have have high alignment.*//* 进行size的内存对齐操作 */if (MALLOC_ALIGNMENT == 2 * SIZE_SZ)size = ALIGN_UP (nb + SIZE_SZ, pagesize); //调整sizeelsesize = ALIGN_UP (nb + SIZE_SZ + MALLOC_ALIGN_MASK, pagesize);//调整sizetried_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 storedin the prev_size field of the chunk. This allows us to adjustreturned start address to meet alignment requirements hereand in memalign(), and still be able to compute properaddress 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 andMALLOC_ALIGN_MASK is 2*SIZE_SZ-1. Each mmap'ed area is pagealigned and therefore definitely MALLOC_ALIGN_MASK-aligned. */assert (((INTERNAL_SIZE_T) chunk2mem (mm) & MALLOC_ALIGN_MASK) == 0);front_misalign = 0;}elsefront_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为0set_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分配内存。
1. 设置老的Top chunk的参数
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的sizeold_end = (char *) (chunk_at_offset (old_top, old_size)); //老的Topchunk的尾部地址/* brk=第一次分配返回值 ;snd_brk=第二次分配返回值 */brk = snd_brk = (char *) (MORECORE_FAILURE); //默认设置分配失败
2. 尝试使用grow_heap函数
如果剩余的空间不足,首先通过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 + 使用中)}
3. 尝试使用new_heap函数
扩容失败,则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指向avheap->prev = old_heap; //指向前一个老的heapav->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 ofMALLOC_ALIGNMENT in size. *//* The fencepost takes at least MINSIZE bytes, because it mightbecome the top chunk again later. Note that a footer is setup, 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_sizeset_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}}
4. 尝试使用try_mmap方式
/* 直接跳转到try_mmap,通过MMAP分配一块内存 */else if (!tried_mmap)/* We can at least try to use to mmap memory. */goto try_mmap;}
四、主分配区分配的实现
如果是主分配区,则直接扩容Top chunk(brk和mmap方式都有)。
1. 设置Top扩容的size值
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 tocombine with new space. We add it back later only ifwe 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 itwith whole-page arguments. And if MORECORE is contiguous andthis is not first time through, this preserves page-alignment ofprevious calls. Otherwise, we correct to page-align below.*///按照页进行对齐 对齐size = ALIGN_UP (size, pagesize);
2. brk分配成功的方式
调用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_hookvoid (*hook) (void) = atomic_forced_read (__after_morecore_hook);if (__builtin_expect (hook != NULL, 0))(*hook)();}
3. brk分配失败采用MMAP分配
进入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 notever rely on contiguous space since this could incorrectlybridge regions.*/set_noncontiguous (av);//主分配区设置不连续的标记,因为这里使用了MMAP分配}}}
五、主分配区分配成功后对齐裁剪操作
主分配区分配成功后,返回brk值为分配的内存地址。
后续如果是brk连续分配地址是相邻的,则直接扩容Top
如果非相邻的,则需要将老的Top chunk剩余的空间释放到bins上,并且经过一定裁剪和对齐之后,返回新的Top chunk。
1. 内存地址连续相邻直接扩容Top
/* 分配成功的情况处理 */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使用中)
2. brk方式分配地址不相邻情况
新分配的内存地址大于原来的top chunk的结束地址,说明地址是不连续的,使用MMAP分配的,则无法直接扩容Top chunk。
有连续标记,说明是brk方式分配的。这里需要将老的Top的空间以及字节对齐的一些冗余空间进行brk二次扩容,放到第一次扩容的尾部。
最终我们要返回两个值:aligned_brk(对齐后的值)和snd_brk(二次扩容的值)
//新分配的内存地址大于原来的top chunk的结束地址,说明地址是不连续的,使用MMAP分配的,则无法直接扩容Top chunkelse{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 becauseprev_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 notbe able to merge with old_top space, so must add to 2nd request.*///correction=新扩展出来的chunk需要继续扩容的大小 包含brk对齐后头部减少的字节 + 老的top的sizecorrection += 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 currentbrk. It might be enough to proceed without failing.Note that if second sbrk did NOT fail, we assume that spaceis contiguous with first sbrk. This is a safe assumption unlessprogram is multithreaded but doesn't use locks and a foreign sbrkoccurred 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)();}}
3. mmap方式分配地址不相邻情况
这里主要调整字节对齐和偏移量。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 becauseprev_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)); //尾部}}
4. 设置调整后的Topchunk
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 agap due to foreign sbrk or a non-contiguous region. Insert adouble fencepost at old_top to prevent consolidation with spacewe don't own. These fenceposts are artificial chunks that aremarked as inuse and are in any case too small to use. We needtwo to make sizes and alignments work out.*//* 合并加工后的的old_top需要回收free */if (old_size != 0){/*Shrink old_top to insert fenceposts, keeping size amultiple of MALLOC_ALIGNMENT. We know there is at leastenough 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 overwriteold_top when old_size was previously MINSIZE. This isintentional. We need the fencepost, even if old_top otherwise getslost.*/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}}}
六、切割新的Topchunk分配内存
如果Top chunk的大小大于分配的值,则进行切割分配操作,切割出来的分配出去,剩余的remainder变成Top chunk。
/* 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函数。
相关文章:
ptmalloc源码分析 - Top chunk的扩容函数sysmalloc实现(09)
目录 一、sysmalloc函数基本分配逻辑 二、强制try_mmap分配方式 三、非主分配区分配的实现 1. 设置老的Top chunk的参数 2. 尝试使用grow_heap函数 3. 尝试使用new_heap函数 4. 尝试使用try_mmap方式 四、主分配区分配的实现 1. 设置Top扩容的size值 2. brk分配成功的…...
[BJDCTF2020]ZJCTF,不过如此 preg_replace /e模式漏洞
目录 preg_replace的/e模式 为什么要变为 {${phpinfo()}} 另一个方法 版本 <?phperror_reporting(0); $text $_GET["text"]; $file $_GET["file"]; if(isset($text)&&(file_get_contents($text,r)"I have a dream")){echo &qu…...
C++day4
1、仿照string类,完成myString 类 #include <iostream> #include <cstring>using namespace std; class myString {private:char *str; //记录c风格的字符串int size; //记录字符串的实际长度public://无参构造myString():size(10…...
【LeetCode-简单题】541. 反转字符串 II
文章目录 题目方法一:双指针 题目 方法一:双指针 题目的意思: 通俗一点说,每隔k个反转k个,末尾不够k个时全部反转; 需要注意右边界的取值 int r Math.min(l k -1,n-1);//取右边界与n-1的最小值 确定边界…...
Linux服务使用宝塔面板搭建网站,并发布公网访问
文章目录 前言1. 环境安装2. 安装cpolar内网穿透3. 内网穿透4. 固定http地址5. 配置二级子域名6. 创建一个测试页面 前言 宝塔面板作为简单好用的服务器运维管理面板,它支持Linux/Windows系统,我们可用它来一键配置LAMP/LNMP环境、网站、数据库、FTP等&…...
代码随想录算法训练营19期第48天
198.打家劫舍 视频讲解:动态规划,偷不偷这个房间呢?| LeetCode:198.打家劫舍_哔哩哔哩_bilibili 代码随想录 初步思路:动态规划。 总结: dp[i]:考虑下标i(包括i)…...
【校招VIP】产品项目分析之竞品分析
考点介绍: 在产品经理的日常工作当中,经常需要针对某个具体问题或特定功能点进行竞品调研;竞品分析是结构化分析方法论,核心思想是通过对比的方法寻找最佳的解决方案。 产品项目分析之竞品分析-相关题目及解析内容可点击文章末尾…...
【JavaScript内置对象】Date对象,从零开始
【JavaScript内置对象】Date对象,从零开始 时间的表示方式 时间表示的基本概念 最初,人们是通过观察太阳的位置来决定时间的,但是这种方式有一个最大的弊端就是不同区域位置大家使用的时间是不一致的。 相互之间没有办法通过一个统一的时间…...
idea启动缓慢解决办法
idea启动缓慢解决办法 文章目录 idea启动缓慢解决办法前言一、修改内存大小二、虚拟机运行大小三、插件禁用1、安卓相关2、构建工具3、Code Coverage 代码覆盖率4、数据库5、部署工具6、html和xml7、ide settings8、JavaScript框架和工具9、jvm框架10、Keymap快捷键映射11、kot…...
App测试中ios和Android有哪些区别呢?
App测试中,大家最常问到的问题就是:ios和 Android有什么区别呢? 在Android端,我们经常会使用 JavaScript、 HTML、 CSS等技术来编写一些简单的 UI界面。而 iOS端,我们经常会使用到 UI设计、界面布局、代码结构、 API等…...
Flink JobManager的高可用配置
背景 在flink执行中,jobManager是一个负责执行流式应用执行和检查点生成的组件,一旦发生故障,那么其负责的所有应用都会被取消,所以我们需要对JobManager配置高可用的模式 JobManager高可用配置 配置JobManager的高可用需要使用…...
为什么Token手动添加到请求的Header中,通常使用“Authorization“字段?
为什么Token手动添加到请求的Header中,通常使用"Authorization"字段? 通常将Token放置在"Authorization"字段中的主要原因如下: 标准化:HTTP协议中定义了一些常见的头部字段,如"Authorizati…...
国际生态数据获取网络
1、https://lternet.edu/ 2、https://www.neonscience.org/ 3、https://www.tern.org.au/ 4、https://www.industry.gov.au/ 5、http://www.cbas.ac.cn/ 6、https://sdg.casearth.cn/datas/casearthData 7、https://data.casearth.cn/ 8、https://omai.casearth.cn/ai-l…...
爬虫逆向实战(34)-某视综数据(MD5、AES)
一、数据接口分析 主页地址:某视综 1、抓包 通过抓包可以发现数据接口是/rank/waiting/fans 2、判断是否有加密参数 请求参数是否加密? 通过查看“载荷”模块可以发现有一个sign参数 请求头是否加密? 无响应是否加密? 通过查…...
数据分析三剑客之Matplotlib
0.Matplotlib绘图和可视化 1.简介 我的前面两篇文章介绍了 Nimpy ,Pandas 。今天来介绍一下Matplotlib。 简单来说,Matplotlib 是 Python 的一个绘图库。它包含了大量的工具,你可以使用这些工具创建各种图形,包括简单的散点图&…...
Python Opencv实践 - LBP特征提取
参考资料: python skimage库LBP提取特征local_binary_pattern参数解释_local_binary_pattern函数_friedrichor的博客-CSDN博客 LBP特征笔记_亦枫Leonlew的博客-CSDN博客 import cv2 as cv import numpy as np import matplotlib.pyplot as plt from skimage.feat…...
Docker 搭建Redis Cluster 集群
环境: centos7 redis:7.0.5 三主三从,六个节点 一、下载redis镜像 docker pull redis:7.0.5 二、创建虚拟网卡 docker network create redis-cluster# 查看创建的Docker网卡 docker network ls 网卡类型为bridge桥接类型 三、准备redis配置文件 redi…...
解决谷歌浏览器会http网站自动变成https的问题
不知道是不是升级的缘故,最近打开公司一个http网站,会自动跳去https,用了网上说的这个方案,如下: 但发现还不行,这时我尝试用点击地址栏左边那锁的那个图标,图如下: 然后点击网站设…...
go小知识2
Golang开发新手常犯的50个错误_gezhonglei2007的博客-CSDN博客 一些题目整理,附带大佬的解释 1.go中哪些值不能寻址& 常量(const常量,字面值3.14,字符串“xxx”,函数或方法, map的val值) golang中接…...
zabbix监控H3C设备
背景 常见的服务和主机已经使用Prometheus进行监控了,但是网络设备还未配置监控。使用基于SNMP对网络设备进行监控。 设备概览 主要类型为H3C的路由器和交换机。 H3CS5560交换机 路由器MER5200 er8300 一台群晖的NAS服务 步骤 配置网络设备开启telnet远程&…...
国产化改造之Mysql迁移方案:Mysql Galera Cluster
一、背景 因某业务系统OS国产化改造,现需将生成环境Mysql 主从迁移到新部署的BCLinux OS主机上;如果保障业务不断,平滑迁移并成功割接将是本次方案的重要方向,现场环境涉及需迁移数据780G左右,目标主机OS版本ÿ…...
bootstrap表单类型
1.基本格式 <form><div class"form-group"><label>电子邮件</label><input type"email" class"form-control" placeholder"请输入你的电子邮件" /></div><div class"form-group"&g…...
第一章 SQL Server 数据库部署
个人简介:云计算网络运维专业人员,了解运维知识,掌握TCP/IP协议,每天分享网络运维知识与技能。座右铭:海不辞水,故能成其大;山不辞石,故能成其高。 个人主页:小李会科技的…...
赛事个人团体报名分组成绩查询证书h5小程序开源版开发
赛事个人团体报名分组成绩查询证书h5小程序开源版开发 以下是赛事个人团体报名分组成绩查询证书H5小程序的功能列表: 用户注册和登录:用户可以通过注册和登录功能创建账号或使用已有账号登录小程序。 赛事信息浏览:用户可以浏览小程序中提供…...
【大数据环境配置】01-安装VMware虚拟机
一、VMware的安装 1: 运行“VMware_workstation_full_12.5.2.exe”(或者其他版本) 2:引导页面,直接点击下一步 3: 同意许可,然后继续点击下一步 4: 选择VMware安装位置࿰…...
什么是C语言中的命名空间?
C语言本身并没有像某些其他编程语言(如C)中的显式命名空间(namespace)的概念,但C语言中有一些机制和约定,允许开发人员组织和管理变量、函数和其他标识符的名称,以避免名称冲突和提高代码可维护…...
Java语言特点 8种基本数据类型 标识符等练习题 插入/希尔/选择/堆/冒泡/快速/归并/计数排序
(单选题)java 的字符类型采用的是 Unicode编码方案,每个 Unicode码占用( )个比特位。 题目内容: A .8 B .16 C .32 D .64 (单选题)下列说法不正确的是( ࿰…...
建站系列(七)--- 常用前后端框架
目录 相关系列文章前言一、何为框架?二、为什么使用框架三、常用框架(一)Bootstrap(二)Layui(三)JQuery(四)Vue.js(四)ThinkPHP(五&am…...
Jmx协议远程连接java服务器
注意:本例里,我用的是jdk17 通常用jdk自带的jconsole,或者想要功能强大点的使用visualVM 需要java服务器在启动的时候加上以下参数 -Dcom.sun.management.jmxremote 启用jxm远程连接-Djava.rmi.server.hostname10.1.3.99 指定jxm监听地址&…...
consul 概念 键值对操作命令
传统配置文件的弊端 静态化配置,例如env文件配置文件无法区分环境配置文件过于分散历史版本无法查看 配置中心如何解决的呢?配置中心的思路是把项目中的配置参数全部放在一个集中的地方来管理,并提供一套标准的接口,当各个服务需要获取配置…...
做化妆品网站怎样/业务网站制作
大家好,我是为人造的智能操碎了心的智能禅师。全文大约1900字。读完可能需要下面这首歌的时间...
wordpress汉化视频模板/百度手机助手下载安装最新版
Java-odbc-000-连接、插入、查询、修改、删除-2020-6-25 目录提示零、最终效果一、准备二、ListDB.java三、SQLDB.java提示 运行环境jdk1.6 零、最终效果 一、准备 ①sample.mdb(利用微软的access) ②管理工具->ODBC数据管理程序(32位)//虽然我电脑是64位->用户DSN-&…...
wordpress代码安装畅言/汽车seo是什么意思
概要 分析如何使用微软提供的ASP.NET来对动态产生的URL地址进行网址重写。 网址重写是实现一种截取网址请求并将其进行处理后重新指向到一个指定的网址的过程。作者本人在对各种实现网址重写的技术进行研究和探讨后得出的经验和方法,希望能对您有所帮助。 内容简…...
甘肃工程造价信息网/深圳seo优化推广
用dos命令创建别人无法进入又无法删除的文件夹 发布时间:2009.10.22 新闻来源:大连华育国际软件培训校区-大连JAVA培训,大连软件培训,大连华育国际,大连.net工程师培训,大连定单培训,就业实训,大连IT教育培训,大连软件人才 浏览次数:7 第一步…...
c2c平台的产品类型/seo短视频网页入口引流
2019独角兽企业重金招聘Python工程师标准>>> import java.io.UnsupportedEncodingException; /** * 转换字符串的编码 */public class ChangeCharset { /** 7位ASCII字符,也叫作ISO646-US、Unicode字符集的基本拉丁块 */ public static final String US_…...
网站源码完整/百度前三推广
目录 简介 安装 单独使用 const store createStore(reducer) store.subscribe(fun) store.getState() store.dispatch(obj) 示例 结合react使用 Provider const mapStateToProps state>(obj) const mapDispatchToProps obj connection 示例 index.js sto…...