baiyan所有视频:https://segmentfault.com/a/11...源视频地址:http://replay.xesv5.com/ll/24...回顾PHP内存分配过程使用gdb回顾PHP内存分配过程首先在_emalloc()函数处设置断点alloc_globals是一个全局变量,可以使用AG宏来访问内部字段接下来观察mm_heap中的字段:size=0,peak=0,表示当前没有使用内存real_size=2097152=2M,表示已经申请了一块内存给操作系统跟进main_chunk字段:内存的地址heap字段与上面mm_heap字段的地址相同,这样可以方便快捷的定位到chunk的mm_heap。注意它的地址是0x7ffff3800040,注意倒数第二位有一个4(十进制为64),也就是说它的起始地址不是正好2MB对齐,而是2MB+64B。为什么是这样?看下图,结构体的前几个字段刚好占据64B,所以heap_slot字段只能从64B的偏移位置开始。-next和prev字段表示双向链表中chunk和chunk之间的链接。当只有一个chunk节点时,next和prev指针都指向自己——free_pages字段为511,表示使用了512页中的一个,剩余511个空闲页——free_map字段为8个uint64_t类型,标记是否每页使用,一共512bit。每个chunk中的512页分为8组,每组64页,正好对应free_map中的每一项,0未使用,1已使用——map字段为512个uint32_t类型,共2KB。用来标记是小内存还是大内存,可以用低位来存储bit_num或者使用页数等信息。这里是大内存,已经使用了一页(存放在mm_heap中)。我们通过gdb,在_emalloc()之后,调用zend_mm_alloc_heap()函数,然后判断大小,这里小于3KB(ZEND_MM_MAX_SMALL_SIZE),所以这里调用了zend_mm_alloc_small()函数,zend_mm_alloc_small_slow()函数也可能被调用,视情况而定。然后计算bin_num,这里size为11,小于64。所以直接返回(size-!!size)>>3,打印结果为1。根据它的bin_num,去bin_data_size数组中找到那个应该分配的大小是16B。一页可分为256个16B,需要一页。这样PHP会取出1个16B返回给用户,剩下的255个16B会挂在free_slot链表上,数组下标为1(下标为0节省8B内存,而下标为1节省16B内存...),再次打印free_slot字段,观察第一个下标已经有元素,可以验证我们的结论。复杂的宏替换针对视频中的bin_data_size数组为什么最后被替换,以及为什么最后bin_data_size数组中只存入了data的size列的问题,为了说明方便,这里简化源码示例:#include
