Linux性能学习(2.4)内存_为什么会预分配很大的虚拟内存及Ptmalloc2

参考资料:
1.2万字|30张图带你领略glibc内存管理精髓(因为OOM导致上千万损失)
2.庄明强老师的《Glibc内存管理》

在上上篇文章《进程线程内存分配机制探究》中提出了三个问题:

  • 第一个问题:64位系统,为什么系统分配的内存比实际申请的内存大16个字节?
  • 第二个问题:64位系统,为什么系统会给进程申请132KB的内存,而不是我们真正需要的内存?
  • 第三个问题:64位系统,为什么系统会给线程申请64MB的内存,而不是我们真正需要的内存?

在上篇文章《为什么分配的内存比申请的内存大16个字节》中,我们解决了第一个问题,这篇文章对后面两个问题进行探究。

在我们上篇文章中下载的glibc源码中,默认使用了一个内存池—Ptmalloc2,内存池用于处理用户申请和释放内存时候,可以高效的进行管理。

当我们是有malloc申请内存时候,Ptmalloc2会预先分配比申请内存更大的空间作为内存池,然后再在内存池中,取出申请的内存给到用户,当用户释放内存时候,内存池会根据一些策略来判断是否释放给系统,如果不释放这块内存,那么就会将这块内存还到内存池中,供下次申请时使用,这样效率会更高。当申请的内存大于当前内存池时候,内存池会继续申请新的内存池来进行管理,一旦申请新的内存池,那么内存池数量就不会减小,即便某块内存池已经完全空闲,也不会减小。

在主进程(主线程)下申请内存时(主分配区),Ptmalloc2会预先分配132KB的内存,叫做Main Arena, 然后从这132KB中进行分配;

在子线程下申请内存时(非主分配区),会预先分配HEAP_MAX_SIZE大小的内存(64位是64MB,32位是1MB),叫做Thread Arean。另外,单个子线程的内存池的数量最大是8倍的CPU数。也可以修改环境变量MALLOC_ARENA_MAX来修改限制。PS:可通过如下指令查看内存池的限制grep MALLOC_ARENA_MAX /proc/$(pid)/environ

当我们使用malloc申请内存时候,会根据申请内存的大小采用不同的分配方式:
如果小于128KB(DEFAULT_MMAP_THRESHOLD),则会使用brk()系统调用来分配,具体是通过移动堆顶的位置来分配内存,用完不会释放,而是归还到内存池中;

如果大于128KB(DEFAULT_MMAP_THRESHOLD),则会使用内存映射mmap()来分配,也就是在文件映射段找一块空闲内存分配出去,释放后还给系统。

看到这里,有个疑问,前面不是说用户malloc时候,会采用内存池的方式分配内存给用户,怎么这里又提到了brk和mmap?

当用户通过malloc方式来申请内存时候,内存池会优先返回内存中的空闲内存,如果内存池中的空闲内存不满足时候,则malloc会通过底层调用brk/mmap等系统调用方式来向系统申请内存。

PS:根据上面的分配方式,主分配区可以使用brk和mmap来分配,而非主分配区只能使用mmap来映射内存块,每次申请则会HEAP_MAX_SIZE大小的内存(64位是64MB,32位是1MB),然后再进行切割给用户使用。

当然,Ptmalloc2的内存分配机制更复杂,上面的描述只是一个大概的描述,有兴趣的可以查看上面参考链接,了解详细的分配机制。

猜你喜欢

转载自blog.csdn.net/u011003120/article/details/128286700
今日推荐