太原公司网站建立,文创产品设计方案ppt,一个网站是如何建设,丽水微信网站建设公司2021年末面试蔚来汽车#xff0c;面试官考察了malloc/free的实现机制。当时看过相关的文章#xff0c;有一点印象#xff0c;稍微说了一点东西#xff0c;不过自己感到不满意。今天尝试研究malloc的实现细节#xff0c;看了几篇博文#xff0c;发现众说纷纭#xff0c;且… 2021年末面试蔚来汽车面试官考察了malloc/free的实现机制。当时看过相关的文章有一点印象稍微说了一点东西不过自己感到不满意。今天尝试研究malloc的实现细节看了几篇博文发现众说纷纭且实现比较复杂。在此对malloc的实现机制进行研究了解其大概的工作机制没有深究细节。
先说结论
内存的分配
可以把内存空间的分配分为两个过程
1从操作系统获取到内存实际获取到的内存一般比进程申请的空间大一些。
2从申请到的空间中拿出来一部分给到进程。
所以一般会有部分备用的内存空间。所以就有了下面的结论。
1.如果进程申请的空间小于备用的空间则直接把内存分配给进程。
2.如果进程申请的空间大于备用的空间
1申请的空间128KB通过系统调用brk在现有地址的基础上扩张即新分配的空间和之前的空间是连续的。
2申请的空间128KB通过mmap在物理内存映射一段空间。
内存的释放 试验环境ubuntu虚拟机gcc:Ubuntu 9.4.0-1ubuntu1~20.04.1
测试代码
#include unistd.h
#include stdio.h
#include stdlib.h
#include malloc.htypedef unsigned char uint8;int main()
{//step1getchar();uint8* p1 (uint8*)malloc(127 * 1024 * sizeof(uint8));printf(p1:%p,size:%ld\n, p1, malloc_usable_size(p1));//step2getchar();free(p1);//step3getchar();uint8* p2 (uint8*)malloc(127 * 1024 * sizeof(uint8));printf(p2:%p,size:%ld\n, p2, malloc_usable_size(p2));//step4getchar();uint8* p3 (uint8*)malloc(127 * 1024 * sizeof(uint8));printf(p3:%p,size:%ld\n, p3, malloc_usable_size(p2));//step5getchar();uint8* p4 (uint8*)malloc(500 * 1024 * sizeof(uint8));printf(p4:%p,size:%ld\n, p4, malloc_usable_size(p4));//step6getchar();uint8* p5 (uint8*)malloc(1024 * sizeof(uint8));printf(p5:%p,size:%ld\n, p5, malloc_usable_size(p5));//step7getchar();free(p5);//step8getchar();free(p4);getchar();return 0;
}
测试方法
1.通过strace跟踪进程执行的过程。
2.通过cat /proc/PID/maps观察堆区的分配情况。
测试过程和分析
strace ./a.out 略 brk(NULL) 0x55c726c6e000 brk(0x55c726c8f000) 0x55c726c8f000 //进程启动之后系统自动分配了0x55c726c8f000-0x55c726c6e000约为400K的内存这部分内存是备用的。
//step1:55c726c6e000-55c726c8f000 [heap] //进程请求分配127K内存由于系统已有400K空余的内存够用所以直接给进程返回一块内存。起始地址为p10x55c726c6e6b0和预留的起始地址相比有一定的偏移量 read(0, \n, 1024) 1 fstat(1, {st_modeS_IFCHR|0620, st_rdevmakedev(0x88, 0), ...}) 0 write(1, p1:0x55c726c6e6b0,size:130056\n, 30p1:0x55c726c6e6b0,size:130056 ) 30
//step2:55c726c6e000-55c726c8f000 [heap] //free(p1),系统只是把这块空间标记为可用的并没有真正的释放其内存空间。 read(0, \n, 1024) 1
//step3:55c726c6e000-55c726c8f000 [heap] //再次请求分配127K的内存备用的内存空间够用同step1,直接分配给进程。 read(0, \n, 1024) 1 write(1, p2:0x55c726c6e6b0,size:130056\n, 30p2:0x55c726c6e6b0,size:130056 ) 30
//step4:55c726c6e000-55c726ccf000 [heap] //再次请求分配129K的内存空间之前剩余的备用空间约为400K-127K-127K146K,不够用了。而且请求分配的内存128K在原来地址的基础上通过brk扩充内存空间即和原来的内存是连续的 read(0, \n, 1024) 1 brk(0x55c726ccf000) 0x55c726ccf000 write(1, p3:0x55c726c8e6d0,size:130056\n, 30p3:0x55c726c8e6d0,size:130056 ) 30
//step5 //55c726c6e000-55c726ccf000 [heap] //f2b3313f000-7f2b331bd000 //再次请求分配500K的内存空间之前剩余的备用空间不够用了,而且请求分配的内存128K通过mmap在物理内存映射一块空间且和原来的空间是不连续的 read(0, \n, 1024) 1 mmap(NULL, 516096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) 0x7f2b3313f000 write(1, p4:0x7f2b3313f010,size:516080\n, 30p4:0x7f2b3313f010,size:516080 ) 28
//step6 //55c726c6e000-55c726ccf000 [heap] //f2b3313f000-7f2b331bd000 //同step1 read(0, \n, 1024) 1 prewrite(1, quot;p5:0x55c726cae2e0,size:1032\nquot;, 28p5:0x55c726cae2e0,size:1032/pre
//step7 //55c726c6e000-55c726ccf000 [heap] //f2b3313f000-7f2b331bd000 //同step2 read(0, \n, 1024) 1
//step8:55c726c6e000-55c726ccf000 [heap] //通过munmap释放内存 read(0, \n, 1024) 1 munmap(0x7f2b3313f000, 516096)