赞
踩
malloc() 分配的是虚拟内存。
如果分配后的虚拟内存没有被访问的话,虚拟内存是不会映射到物理内存的,这样就不会占用物理内存了。
只有在访问已分配的虚拟地址空间的时候,操作系统通过查找页表,发现虚拟内存对应的页没有在物理内存中,就会触发缺页中断,然后操作系统会建立虚拟内存和物理内存之间的映射关系。
malloc() 在分配内存的时候,并不是老老实实按用户预期申请的字节数来分配内存空间大小,而是会预分配更大的空间作为内存池。
- #include <stdio.h>
- #include <malloc.h>
-
- int main() {
- printf("使用cat /proc/%d/maps查看内存分配\n",getpid());
-
- //申请1字节的内存
- void *addr = malloc(1);
- printf("此1字节的内存起始地址:%x\n", addr);
- printf("使用cat /proc/%d/maps查看内存分配\n",getpid());
-
- //将程序阻塞,当输入任意字符时才往下执行
- getchar();
-
- //释放内存
- free(addr);
- printf("释放了1字节的内存,但heap堆并不会释放\n");
-
- getchar();
- return 0;
- }

大约分配16KB ,为什么打印的地址比mmap映射的地址多10个Byte?
是因为free()调用的时候,因为分配地址的时候就多了10Byte的头部用来描述分配到内容,所以free不需要额外的地址。
这是因为与其把这 1 字节释放给操作系统,不如先缓存着放进 malloc 的内存池里,当进程再次申请 1 字节的内存时就可以直接复用,这样速度快了很多。
当然,当进程退出后,操作系统就会回收进程的所有资源。
频繁通过 mmap 分配的内存话,不仅每次都会发生运行态的切换,还会发生缺页中断(在第一次访问虚拟地址后),这样会导致 CPU 消耗较大。
通过 brk() 系统调用在堆空间申请内存的时候,由于堆空间是连续的,所以直接预分配更大的内存来作为内存池,当内存释放的时候,就缓存在内存池中。
等下次在申请内存的时候,就直接从内存池取出对应的内存块就行了,而且可能这个内存块的虚拟地址与物理地址的映射关系还存在,这样不仅减少了系统调用的次数,也减少了缺页中断的次数,这将大大降低 CPU 的消耗。
当执行 free() 函数时,free 会对传入进来的内存地址向左偏移 16 字节,然后从这个 16 字节的分析出当前的内存块的大小,自然就知道要释放多大的内存
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。