内存管理
malloc 函数申请内存, 返回指针;
free 释放内存
1 | void * ptr = malloc(size); |
问题: 申请内存的时候需要传入 size, 为什么 free 的时候没有传入 size, 那么是怎么做到准确释放 size 大小的内存的呢?
其实呢, malloc 在分配内存的时候, 返回的地址的指针指向了程序可用内存的位置, 在 ptr 前面会多分配 32 位的头部, 头部的低三位表示是否分配。
当 free 的时候,会向前搜寻 32 的头,取高 29 位为块的大小,所以 free 的时候就不需要传递 size 了,当然这只是一种 malloc 的实现,当前的 linux 的 malloc 事件已经不是这样了,但原理是一样的,也是维护了一个头部。
基本概念
- chunk
- page
- 各种规格的内存
chunk:2MB 大小的内存;
page:4KB 大小的内存;
一个 chunk 可以分成 512 个 page。
内存规格
- small (size <= 3KB)30 个规格
- large (3KB < size < 2MB-4KB) large 是 4K 的整数倍
- huge (size > 2MB - 4KB) huge 一定是 2M 的整数倍, 例如申请 3M 内存, 那么返回的一定是比 3M 大,且是 2M 的整数倍, 是 4M
内存分配
zend_mm_alloc_heap 判断申请内存的大小;
申请内存大于 2M-4K, 则属于 huge, 执行 zend_mm_alloc_huge, 调用 zend_mm_chunk_alloc, 最终调用 mmap 取申请大内存;
申请内存大于 3K 且小于 2M-4K, 则属于 large, 执行 zend_mm_alloc_large, 调用 zend_mm_alloc_pages
申请内存小于等于 3K, 则属于 small, 执行 zend_mm_alloc_small 函数, 如果当前有 small 内存, 则直接返回, 如果没有, 则执行 zend_mm_alloc_small_slow, 需要先去 zend_mm_alloc_pages 看看, 如果 large 也没有余量了, 就去 zend_mm_chunk_alloc 开辟新的内存。
small 内存管理
chunk 内存对齐
4k 对其:申请的内存只能是 4K 的整数倍;
内存对其的好处,当已知一个内存地址,就可以算出此内存(page)的起始地址;例如有一内存地址 0x103c61120,4k 对齐,通过宏计算,此内存所在 page 的起始地址为 0x103c61000,在此 page 的偏移量是 0x120,能过快速定位内存地址所在的 page,提高效率。
内存管理的代码比较多,但是我们只需要掌握两个核心:当我们 free 的时候,不需要传递 size,