SEO案例网站建设价格,大连网站建设找哪家,哈尔滨建站模板展示,推广链接点击器app目录
一、heap_info是什么#xff1f;
二、heap_info结构图
三、new_heap的实现
四、grow_heap的实现
五、shrink_heap的实现
六、delete_heap的实现 一、heap_info是什么#xff1f; 上一章节《ptmalloc源码分析 - 多线程争抢竞技场Arena的实现#xff08;04#xf…目录
一、heap_info是什么
二、heap_info结构图
三、new_heap的实现
四、grow_heap的实现
五、shrink_heap的实现
六、delete_heap的实现 一、heap_info是什么 上一章节《ptmalloc源码分析 - 多线程争抢竞技场Arena的实现04》我们讲解了多线程环境下面对线程之间的竞争ptmalloc除了主分配区外还会去创建非主分配区。因为线程在调用malloc的时候首先会去获取一个分配区如果当前的分配区都被锁定并且没有新的分配区可用的时候ptmalloc就会去创建一个新的非主分配区。
我们也从上一章节知道了非主分配区的几个特性
每个进程有一个主分配区也可以允许有多个非主分配区。主分配区可以使用brk和mmap来分配而非主分配区只能使用mmap来映射内存块非主分配区的数量一旦增加则不会减少。主分配区和非主分配区形成一个环形链表进行管理。通过malloc_state-next来链接
在函数_int_new_arena中主要是创建一个新的分配区该分配区主要是非主分配区类型。主分配区在ptmalloc_init中初始化并且设置了全局变量main_arena的值。而_int_new_arena中主要调用的是new_heap来创建和初始化一个非主分配区。
这里主要包含几个部分: _heap_info非主分配区的结构体 new_heap(size_t size, size_t top_pad)创建一个新的非主分配区 grow_heap(heap_info *h, long diff)扩大一个分配区的size shrink_heap(heap_info *h, long diff)缩小一个分配区的size delete_heap(heap)删除一个分配区结构 二、heap_info结构图 _heap_info来存储分配区的基础信息 ar_ptr指向当前heap所属的竞技场Arena prev链表指向前一个堆的heap_info结构 size当前分配区大小 mprotect_size记录了堆中多大的空间是可读写的 pad通过一个数组的方式包含该heap_info结构体所需要的内存地址。并且能够按照0x10字节对齐(x86中则是8字节对齐)
typedef struct _heap_info {mstate ar_ptr; /* 指向当前heap所属的竞技场Arena Arena for this heap. */struct _heap_info *prev; /* 链表指向前一个堆的heap Previous heap. */size_t size; /* 当前分配区大小 Current size in bytes. */size_t mprotect_size; /* 记录了堆中多大的空间是可读写的 Size in bytes that has been mprotectedPROT_READ|PROT_WRITE. *//* Make sure the following data is properly aligned, particularlythat sizeof (heap_info) 2 * SIZE_SZ is a multiple ofMALLOC_ALIGNMENT. *//* 用以堆其该结构体使其能够按照0x10字节对齐(x86中则是8字节对齐) */char pad[-6 * SIZE_SZ MALLOC_ALIGN_MASK];
} heap_info;
三、new_heap的实现 new_heap函数说明创建一个新的堆空间 从 mmap 区域映射一块内存页来作为 heap
映射内存页的大小 在 32 位系统上该函数每次映射 1M 内存映射的内存块地址按 1M 对齐 在 64 为系统上该函数映射 64M 内存映射的内存块地址按 64M 对齐。
/* HEAP_MIN_SIZE 和 HEAP_MAX_SIZE 最小和最大值*/
/* HEAP_MAX_SIZE根据操作系统取值32位 1M64位 64M*/
#define HEAP_MIN_SIZE (32 * 1024)
#ifndef HEAP_MAX_SIZE
# ifdef DEFAULT_MMAP_THRESHOLD_MAX
# define HEAP_MAX_SIZE (2 * DEFAULT_MMAP_THRESHOLD_MAX)
# else
# define HEAP_MAX_SIZE (1024 * 1024) /* must be a power of two */
# endif
#endif/* DEFAULT_MMAP_THRESHOLD_MAX 定义不同操作系统下的值大小 */
# if __WORDSIZE 32
# define DEFAULT_MMAP_THRESHOLD_MAX (512 * 1024) //512K
# else
# define DEFAULT_MMAP_THRESHOLD_MAX (4 * 1024 * 1024 * sizeof(long)) //32M
# endif
#endif
new_heap函数实现逻辑
首先判断默认设置的size大小如果size需要在HEAP_MIN_SIZE和HEAP_MAX_SIZE之间64位系统HEAP_MIN_SIZE32kHEAP_MAX_SIZE64M。如果size设置过大则报错如果过小则默认使用HEAP_MIN_SIZE作为size的最小值创建内存映射区域的时候使用MMAP函数。每次分配以HEAP_MAX_SIZE为每一页的大小64位系统 分配一次64M默认情况下aligned_heap_area值为NULL所以代码会直接进入p1的分配流程。p1的分配流程中会一次性分配HEAP_MAX_SIZE*2两个页如果分配成功则将aligned_heap_area设置成第2页的起始位置当第二次进来分配的时候aligned_heap_area值不为空说明前面已经分配过一次并且aligned_heap_area保存了前一次分配第二页的起始地址所以这次分配直接使用前一次分配的第二页。如果此次分配失败则继续跳转到p1重新分配。如果p1分配两个页失败则尝试分配1个页大小HEAP_MAX_SIZE如果还是失败则报错
/* 创建一个新的堆空间 从 mmap 区域映射一块内存页来作为 heap* 分配的页大小* 在 32 位系统上该函数每次映射 1M 内存映射的内存块地址按 1M 对齐* 在 64 为系统上该函数映射 64M 内存映射的内存块地址按 64M 对齐。*/
static heap_info *
new_heap(size_t size, size_t top_pad) {size_t pagesize GLRO(dl_pagesize);char *p1, *p2;unsigned long ul;heap_info *h;/* size 在 HEAP_MIN_SIZE 和 HEAP_MAX_SIZE之间最小HEAP_MIN_SIZE超过HEAP_MAX_SIZE 则返回0 */if (size top_pad HEAP_MIN_SIZE)size HEAP_MIN_SIZE;else if (size top_pad HEAP_MAX_SIZE)size top_pad;else if (size HEAP_MAX_SIZE)return 0;elsesize HEAP_MAX_SIZE;size ALIGN_UP(size, pagesize);/* A memory region aligned to a multiple of HEAP_MAX_SIZE is needed.No swap space needs to be reserved for the following largemapping (on Linux, this is the case for all non-writable mappingsanyway). *//* aligned_heap_area: 是上一次调用 mmap 分配内存的结束虚拟地址并已经按照 HEAP_MAX_SIZE 大小对齐。* 如果aligned_heap_area不为空则从上次虚拟内存地址开始映射HEAP_MAX_SIZE大小的地址 */p2 MAP_FAILED;if (aligned_heap_area) {p2 (char *) MMAP(aligned_heap_area, HEAP_MAX_SIZE, PROT_NONE,MAP_NORESERVE);aligned_heap_area NULL;if (p2 ! MAP_FAILED ((unsigned long) p2 (HEAP_MAX_SIZE - 1))) {__munmap(p2, HEAP_MAX_SIZE);p2 MAP_FAILED;}}/* 如果第一次分配aligned_heap_areaNULL 或者 P2分配失败aligned_heap_area不为NULL则开始重新分配* p1表示第一次分配调用MMAP分配2倍HEAP_MAX_SIZE的内存映射块本次使用内存块的第一块部分并将aligned_heap_area指向第二块部分* */if (p2 MAP_FAILED) {p1 (char *) MMAP(0, HEAP_MAX_SIZE 1, PROT_NONE, MAP_NORESERVE); //分配一块两倍HEAP_MAX_SIZE大小的内存映射块可以分两次使用if (p1 ! MAP_FAILED) { //分配成功p2 (char *) (((unsigned long) p1 (HEAP_MAX_SIZE - 1)) ~(HEAP_MAX_SIZE - 1));ul p2 - p1;if (ul)__munmap(p1, ul);elsealigned_heap_area p2 HEAP_MAX_SIZE; //aligned_heap_area 记录下一次分配的地址值__munmap(p2 HEAP_MAX_SIZE, HEAP_MAX_SIZE - ul);} else {/* 如果P1分配2倍的HEAP_MAX_SIZE失败则再次重试分配HEAP_MAX_SIZE分配失败则报错*//* Try to take the chance that an allocation of only HEAP_MAX_SIZEis already aligned. */p2 (char *) MMAP(0, HEAP_MAX_SIZE, PROT_NONE, MAP_NORESERVE);if (p2 MAP_FAILED)return 0;if ((unsigned long) p2 (HEAP_MAX_SIZE - 1)) {__munmap(p2, HEAP_MAX_SIZE);return 0;}}}if (__mprotect(p2, size, PROT_READ | PROT_WRITE) ! 0) {__munmap(p2, HEAP_MAX_SIZE);return 0;}h (heap_info *) p2; //写入heap_info结构h-size size; //设置大小h-mprotect_size size; //设置大小LIBC_PROBE(memory_heap_new, 2, h, h-size);return h;
}四、grow_heap的实现 grow_heap对堆进行扩容但是size需要小于分配页的大小HEAP_MAX_SIZE 实际就是调整size扩大size但是size需要小于分配页大小
/*** 对堆进行扩容但是size需要小于分配页的大小HEAP_MAX_SIZE* 实际就是调整size扩大size但是size需要小于分配页大小*/
static int grow_heap(heap_info *h, long diff) {size_t pagesize GLRO(dl_pagesize);long new_size;diff ALIGN_UP(diff, pagesize);new_size (long) h-size diff;if ((unsigned long) new_size (unsigned long) HEAP_MAX_SIZE)return -1;if ((unsigned long) new_size h-mprotect_size) {if (__mprotect((char *) h h-mprotect_size,(unsigned long) new_size - h-mprotect_size,PROT_READ | PROT_WRITE) ! 0)return -2;h-mprotect_size new_size;}h-size new_size;LIBC_PROBE(memory_heap_more, 2, h, h-size);return 0;
}
五、shrink_heap的实现 shrink_heap缩小堆区实际就是缩小size通过MMAP函数参数MAP_FIXED
static int shrink_heap(heap_info *h, long diff) {long new_size;new_size (long) h-size - diff;if (new_size (long) sizeof(*h))return -1;/* Try to re-map the extra heap space freshly to save memory, and make itinaccessible. See malloc-sysdep.h to know when this is true. */if (__glibc_unlikely(check_may_shrink_heap())) {if ((char *) MMAP((char *) h new_size, diff, PROT_NONE, MAP_FIXED) //丢弃操作 (char *) MAP_FAILED)return -2;h-mprotect_size new_size;} else__madvise((char *) h new_size, diff, MADV_DONTNEED);/*fprintf(stderr, shrink %p %08lx\n, h, new_size);*/h-size new_size;LIBC_PROBE(memory_heap_less, 2, h, h-size);return 0;
}
六、delete_heap的实现 /* Delete a heap. */#define delete_heap(heap) \do { \if ((char *) (heap) HEAP_MAX_SIZE aligned_heap_area) \aligned_heap_area NULL; \__munmap ((char *) (heap), HEAP_MAX_SIZE); \} while (0)