glibc提供了malloc函数来动态分配内存,我们只知道调用malloc会返回给我们一个指针,指向一块内存空间或NULL,那么malloc的工作原理是什么呢?
概述:
1.小于128kB的空间,使用内存池(在堆上)或brk或sbrk系统调用在堆上分配
2.大于128kB的空间,使用mmap在文件映射区分配
+-----------------------+ High Address | 栈 (Stack) | |-----------------------| | | | 映射区域 | | (mmap) | | | |-----------------------| | 堆 (Heap) | |-----------------------| | BSS段 | |-----------------------| | 数据段 | |-----------------------| | 代码段 | +-----------------------+ Low Address
详细介绍
内存分配机制
- 小于128 KB的内存分配:
- 对于小于128 KB的内存分配请求,glibc的内存分配器通常会使用
brk
系统调用来增加程序的堆(heap)空间。堆是从进程的虚拟内存空间中分配的连续内存区域。通过brk
或sbrk
系统调用,内存分配器可以调整程序数据段(data segment)的大小,从而增加或减少堆的大小。 - 此外,glibc还可能使用内存池(memory pool,也叫arena)来管理小块内存的分配和释放,以减少频繁的系统调用带来的开销。内存池是一种缓存策略,通过预先分配一大块内存,然后在其中管理多个小块内存的分配。
- 大于128 KB的内存分配:
- 对于大于128 KB的内存分配请求,glibc的内存分配器通常会使用
mmap
系统调用。mmap
可以直接从内核请求一块内存区域,并将其映射到进程的虚拟地址空间。与brk
不同,mmap
分配的内存区域不必是连续的,且可以独立于堆的管理。使用mmap
的一个好处是,当内存被释放时,内核可以立即回收这些内存。
brk 和 mmap 的区别
- brk/sbrk
- 优点:管理简单,分配连续的内存区域。
- 缺点:堆的大小受限于进程的内存布局,调整堆大小可能会受到其他内存段的限制。
- mmap
- 优点:可以分配任意大小的内存区域,不需要是连续的。适用于大块内存的分配,可以避免堆空间的碎片化。
- 缺点:开销稍大,因为需要进行内核态的系统调用。