【操作系统】malloc是如何分配内存的?

1.malloc是如何分配内存的?

实际上,malloc()并不是系统调用,而是C库的函数,用于动态分配内存。

malloc申请内存的时候,会有两种方式向操作系统申请堆内存。

  • 方式一:通过brk()系统调用从堆分配内存
  • 方式二:通过mmap()系统调用在文件映射区域分配内存;

方式一实现的方式很简单,就是通过brk()函数将堆顶指针向高地址移动,获得新的内存空间。

方式二通过mmap()系统调用中私有匿名映射的方式,在文件映射区分配一块内存,,也就是从文件映射区投了一块内存。

什么场景malloc()会通过brk()分配内存?又是什么场景通过mmap()分配内存?

malloc()源码里默认定义了一个阈值:

  • 如果用户分配的内存小于128KB,则通过brk()申请内存;
  • 如果用户分配的内存大于128KB,则通过mmap()申请内存;

注意,不同的glibc版本定义的阈值也是不同的。

malloc()分配的是物理内存么?

不是的,malloc()分配的是虚拟内存。

如果分配后的虚拟内存没有被访问的话,是不会将虚拟内存映射到物理内存的,这样就不会占用物理内存了。

只有在访问已分配的虚拟地址空间的时候,操作系统通过查找页表,发现虚拟内存对应的页没有在物理内存中,就会触发中断,然后操作系统会建立虚拟内存和物理内存之间的映射关系。

malloc(1)会分配多大的虚拟内存?

malloc()在分配内存的时候,并不是老老实实按用户预期申请的字节数来分配内存空间大小,而是会预分配更大的空间作为内存池。

具体会预分配多大的空间,跟malloc使用的内存管理器有关系,我们就以malloc默认的内存管理器(Ptmalloc2)来分析。

通过实验,我们可以知道malloc(1)实际上预分配132K字节的内存。

free释放内存,会归还给操作系统么?

通过free释放内存后,堆内存还是存在的,并没有归还给操作系统。

这是因为预期把这1字节释放给操作系统,不如先缓存着放进malloc的内存池里,当进程再次申请1字节的内存时就可以直接复用,这样速度快了很多。

当然,当进程退出后,操作系统就会回收进程的所有资源。

上面说的free内存后堆内存还存在,是针对malloc通过brk()方式申请的内存的情况。

如果malloc通过mmap方式申请的内存,free释放内存后就会归还给操作系统。

为什么不全部使用mmap来分配内存?

因为向操作系统申请内存,是要通过系统调用的,执行系统调用是要进入内核态的,然后再回到用户态,运行态的切换会消耗不少时间。

所以,申请内存的操作应该避免频繁的系统调用,如果都用mmap来分配内存,等于每次都要执行系统调用。

另外,因为mmap分配的内存每次释放的时候,都会归还给操作系统,于是每次mmap分配的虚拟地址都是缺页状态的,然后再第一次访问该虚拟地址的时候,就会触发缺页中断。

也就是说,频繁通过mmap分配的内存,不仅每次都会发生运行态的切换,还会发生缺页中断(在第一次访问虚拟地址后),这样会导致CPU消耗较大。

为了改进这两个为问题,malloc通过brk()系统调用在堆空间申请内存的时候,由于堆空间是连续的,所以直接预分配更大的内存来作为内存池,当内存释放的时候,就缓存在内存池中。

等下次在申请内存的时候,就直接从内存池取出对应的内存块就行了,而且可能这个内存块的虚拟地址与物理地址的映射关系还存在,这样不仅减少了系统调用的次数,也减少了缺页中断的次数,这将大大降低CPU的消耗。

为什么不全部使用brk来分配?

前面我们提到通过brk从堆空间分配的内存,并不分钟归还给操作系统,那么我们考虑这样一个场景:如果我们连续申请了10k,20k,30k这三片内存,如果10k和20k这两片释放了,变为了空闲内存空间,如果下次申请的内存小于30k,那么就可以重用这个空闲的内存空间。

但是如果下次申请的内存大于30k,没有可用的空闲内存空间,必须向OS申请,实际使用内存继续增大。

因此,随着系统频繁地malloc和free,尤其对于小块内存,堆内将产生越来越多的不可用的碎片,导致“内存泄漏”。而这种“泄漏”现象使用valgrind是无法检测出来的。

所以,malloc实现中,充分考虑了brk和mmap行为上的差异及优缺点,默认分配大块内存(12KB)才使用mmap分配内存空间。

free()函数只传入一个内存地址,为什么能知道要释放多大的内存?

实际上,malloc返回给用户态的内存起始地址比进程的堆空间起始地址多了16字节.这个多出来的16字节就是保存了该内存块的描述信息,比如有该内存块的大小。

这样当执行free()函数时,free会对传进入的内存地址向左偏移16字节,然后从这个16字节的分析出当前的内存块的大小,自然就知道要释放多大的内存了。

  • 11
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值