2015年,PHP7的发布可以说是在技能圈里引起了不小的轰动,由于它的实行效率比PHP5直接翻了一倍。
PHP7在内存方面,你是否知道作者都进行了哪些优化?你是否能够深层次理解到作者优化思路的精髓?

让我们从几个核心的数据构造改进开始看起。

PHP7 zval变革

1、php5.3中的zval:

php内存优化PHP7内存机能优化的思惟精华 CSS

我们这里只谈论64位操作系统下的情形。
该zval_struct构造体中的由四个成员构成,个中zvalue_value轻微繁芜一些,是一个联合体。
联合体中最长的成员是一个指针加一个int,8+4=12字节
但是默认情形下,会进行内存对齐,故zval_struct会占用16字节。
那么

末了再考虑下内存对齐,实际占用24字节。
(如果算的有点晕话,感兴趣的同学可以写段大略的测试代码,利用sizeof查看一下)

2、PHP7.2中的zval

7.2中的zval_struct构造体里由3个成员构成,个中zend_value看起来比较繁芜,实际上只是一个8字节的联合体。
u1也是一个联合体,占用是4个字节。
u2也一样。
这样zval_struct就实际占用16个字节。

PHP7 HashTable变革

1、PHP5.3里的HashTable:

再5.3里HashTable便是一个大struct, 有点小繁芜,我们拆开了细说,

uint nTableSize 4字节uint nTableMask 4字节uint nNumOfElements 4字节,ulong nNextFreeElement 8字节 把稳这前面的4个字节会被摧残浪费蹂躏掉,由于nNextFreeElement的开始地址须要对齐Bucket pInternalPointer 8字节Bucket pListHead 8字节Bucket pListTail 8字节Bucket arBuckets 8字节dtor_func_t pDestructor 8字节zend_bool persistent 1字节unsigned char nApplyCoun 1字节zend_bool bApplyProtection 1字节

终极

再加上构造体本身要对齐到8的整数倍,以是实际占用72字节。

2、PHP7.2里的HashTable:

在7.2里HashTable

zend_refcounted_h gc 看起来唬人,实际便是个long,占用8字节union... u 占用4字节uint32_t 占用4字节Bucket 指针占用8字节uint32_t nNumUsed 占用4字节uint32_t nNumOfElements 占用4字节uint32_t nTableSize 占用4字节uint32_t nInternalPointer 占用4字节zend_long nNextFreeElement 占用8字节dtor_func_t pDestructor 占用8字节

占用56字节,并且恰好达到了内存对齐的状态,没有额外的摧残浪费蹂躏。

其余还有PHP源代码里常常出镜的Buckets也从72低落到了32字节,这里我就不翻源代码了。

优化思路精髓

我们看了两个核心数据构造的构造体变革,这上面的优化都是什么含义呢? 拿HashTable举例,貌似从72字节优化到了56字节,这内存节约的也不是特殊多嘛,才20%多而已!

这中间实在有两个缘故原由。

第一、CPU在向内存要数据的时候因此Cache Line为单位进行的,而我们说过Cache Line的大小便是64字节。
回过分来看HashTable,在7.2里的56字节,只须要CPU向内存进行一次Cache Line大小的burst IO,就够了。
而在5.3里的72字节,虽然只比Cache Line大了那么一丢丢,但是对不起,必须得进行两次burst IO才可以。
以是,在打算机里,72字节相对56字节实际上是翻倍的性能提升!

第二、CPU的L1、L2、L3的容量是固定的几十K或者几M。
假设Cache的都是HashTable,那么Cache容量不变的条件下,PHP7里能Cache住的HashTable数量将会翻倍,缓存命中率提升一大截。
要知道L1命中后只须要1ns多一点的耗时,而如果穿透到内存的话可能就须要40多纳秒的延时了,整整差了几十倍。

以是PHP内核的作者大牛深谙CPU与内存的事情事理,表面上看起来只是几个字节的节约,但是实际上爆发出了巨大的性能提升!