内存管理

malloc 函数申请内存, 返回指针;

free 释放内存

1
2
void * ptr = malloc(size);
free(ptr)

问题: 申请内存的时候需要传入 size, 为什么 free 的时候没有传入 size, 那么是怎么做到准确释放 size 大小的内存的呢?

其实呢, malloc 在分配内存的时候, 返回的地址的指针指向了程序可用内存的位置, 在 ptr 前面会多分配 32 位的头部, 头部的低三位表示是否分配。

当 free 的时候,会向前搜寻 32 的头,取高 29 位为块的大小,所以 free 的时候就不需要传递 size 了,当然这只是一种 malloc 的实现,当前的 linux 的 malloc 事件已经不是这样了,但原理是一样的,也是维护了一个头部。

基本概念

  1. chunk
  2. page
  3. 各种规格的内存

chunk:2MB 大小的内存;

page:4KB 大小的内存;

一个 chunk 可以分成 512 个 page。

内存规格

  1. small (size <= 3KB)30 个规格
  2. large (3KB < size < 2MB-4KB) large 是 4K 的整数倍
  3. 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,