chunk由512个page组成,其中第一个page用于保存chunk结构,剩下的511个page用于内存分配,page主要用于Large、Small两种内存的分配;heap是表示内存池的一个结构,它是最主要的一个结构,用于管理上面三种内存的分配,Zend中只有一个heap结构。
struct _zend_mm_heap {
#if ZEND_MM_STAT
size_t size; //当前已用内存数
size_t peak; //内存单次申请的峰值
#endif
zend_mm_free_slot *free_slot[ZEND_MM_BINS]; // 小内存分配的可用位置链表,ZEND_MM_BINS等于30,即此数组表示的是各种大小内存对应的链表头部
...
zend_mm_huge_list *huge_list; //大内存链表
zend_mm_chunk *main_chunk; //指向chunk链表头部
zend_mm_chunk *cached_chunks; //缓存的chunk链表
int chunks_count; //已分配chunk数
int peak_chunks_count; //当前request使用chunk峰值
int cached_chunks_count; //缓存的chunk数
double avg_chunks_count; //chunk使用均值,每次请求结束后会根据peak_chunks_count重新计算:(avg_chunks_count+peak_chunks_count)/2.0
}
struct _zend_mm_chunk {
zend_mm_heap *heap; //指向heap
zend_mm_chunk *next; //指向下一个chunk
zend_mm_chunk *prev; //指向上一个chunk
int free_pages; //当前chunk的剩余page数
int free_tail; /* number of free pages at the end of chunk */
int num;
char reserve[64 - (sizeof(void*) * 3 + sizeof(int) * 3)];
zend_mm_heap heap_slot; //heap结构,只有主chunk会用到
zend_mm_page_map free_map; //标识各page是否已分配的bitmap数组,总大小512bit,对应page总数,每个page占一个bit位
zend_mm_page_info map[ZEND_MM_PAGES]; //各page的信息:当前page使用类型(用于large分配还是small)、占用的page数等
};
//按固定大小切好的small内存槽
struct _zend_mm_free_slot {
zend_mm_free_slot *next_free_slot;//此指针只有内存未分配时用到,分配后整个结构体转为char使用
};
chunk、page、slot三者的关系:
接下来看下内存池的初始化以及三种内存分配的过程。