baiyan所有视频:https://segmentfault.com/a/11...源视频地址:http://replay.xesv5.com/ll/24...回顾一下宏的用法:typedefstruct_zend_alloc_globals{zend_mm_heap*mm_heap;}zend_alloc_globals;...#defineAG(v)(alloc_globals.v)staticzend_alloc_globalsalloc_globals;这个带参数的宏得到了zend_alloc_globals结构体类型中的zend_mm_heap结构体字段,比如AG(mm_heap)=alloc_globals.mm_heap宏就是一个替换。结构和结构内存对齐结构先看一段结构代码struct.c:#includeintmain(){structa{chara;诠释乙;长c;空*d;诠释;字符*f;}s;s.a='c';s.b=1;s.c=22l;s.d=NULL;se=1;s.f=&s.a;printf("sizeofstructais%d",(int)sizeof(s));}编译:gcc-gstruct.c-ostruct运行:./struct,sizeof(a)打印结果为:40执行gdb调试这个结构:这里我们可以看到第一行是所有结构变量的初始值。请注意,指针变量是一个随机地址。在给s.d赋值的过程中,地址变成了0x0,这是一个特殊的地址值,代表NULL。另外,我们注意到结构体s的地址和a变量的地址是一样的。用一个表达式来表达上面的结论:&s=&s.a=fors=s.a=*f结构体内存对齐核心结论:是编译器做的优化,用空间换时间的思想。对齐:按照结构体所有字段的最小公倍数对齐(如果最小公倍数是8B,则按8B对齐;如果是4B,则按4B对齐),与结构体的排列顺序有关领域。如图:我们用gdb来验证上面的结论,还是用上面相同的代码:我们看到变量a的起始地址是150,b的地址是154,很明显是对齐的。如果没有对齐,b的地址应该是151,说明a和b之间有3B的空间。c的地址是158,是下一个8B的起始地址,d的地址是160(注意这里是16进制,只有158+8=160时才会进位),证明c占8B,下面的d变量也同样占用8B。注意e变量,它是一个int,如果不对齐,应该只占4B。并且占用170(f的起始地址)-168(e的起始地址)=8B,所以必须内存对齐。注意一种特殊情况:如果b是char类型,则直接跟前面的char,如图:注意这里的地址都是逻辑地址,每次编译后的逻辑地址都是一样的,但物理地址不同。的。注:如果顺序颠倒,b和c调换,就变成8B(a)+8B(c)+8B(b)+8B(d)+8B(e)+8B(f)=48B注:一定是所有字段的最小公倍数是多少字节,按几个字节对齐。我们来看结构体中只有char类型变量的情况:#includeintmain(){structa{chara;字符b;字符c;}s;s.a='c';s.b='b';sc='a';printf("sizeofstructais%d\n",(int)sizeof(s));}在这个结构体中,只编译运行char类型变量,输出sizeof(s)为:3.为什么不是4还是8?因为1、1、1的最小公倍数是1,所以按照1B对齐,而不是按照4B、8B对齐。同理,如果都是int类型的变量,那么sizeof(s)的结果就是12,也很好理解组合体核心结论:所有union字段共享一个内存空间。整个联合占用的空间是所有字段单独占用空间最大的字段。同样先看一段代码:#includeintmain(){uniona{chara;诠释乙;长c;空*d;诠释;字符*f;}s;s.a='c';s.b=1;s.c=22l;s.d=NULL;se=1;s.f=&s.a;printf("sizeofstructais%d",(int)sizeof(s));}这段代码和前面的struct是一样的代码只是把struct改成了union,其他不变编译运行。输出sizeof(a)的结果为:8我们用gdb调试一下这段代码:可以看到,后面的变量赋值时,会覆盖前面的变量。查看每个变量的地址,我们可以清楚地看到所有变量的起始地址都是相同的。其他注意事项:void*类型的变量可以直接访问其内容吗?答:不能,其他类型的指针变量的内容是可以获取到的,因为记录的是当前类型的长度,而void*类型是没有长度的,所以不能直接获取到,除非强制类型转换或者指定长度用过的。扩展:所有的PHP变量都是基于zval的,zval由3个union(zend_value,u1,u2)组成。这里不展开大小端:大端:也叫高端,即数据端(低位)放在高地址小端:也叫低端,即数据端数据(低位)放在低地址。网络字节序是big-endian,网络字节序是big-endian。因此,小端机器需要将接收到或发送的数据包由大到小进行转换。如何判断是big-endian还是little-endian:参考:使用指针判断机器大小的两种实现:int是4字节,强行转成char类型,取低1字节,如果正好为0x78,则表示低1字节恰好有低地址,即littleendian。如果取低1字节的结果是0x12,则低1字节为高地址,即bigendian。intmain(){inti=0x12345678;如果(*(char*)&i==78){printf("littleendian");}else{printf("大端");和指针方法一样,利用了union共享同一个存储空间的特点。intmain(){unionw{inta;字符b;}C;c.a=1;如果(c.b==1){printf("小端");}else{printf("大端");}}使用gdb观察PHP内存分配情况,示例代码: