ハッシュテーブル
PHP 7ではハッシュテーブルも高速化されています。ハッシュテーブルとバケットの構造体を比較してみましょう。まずはPHP 5からです。
typedef struct bucket {
ulong h;
uint nKeyLength;
void *pData;
void *pDataPtr;
struct bucket *pListNext;
struct bucket *pListLast;
struct bucket *pNext;
struct bucket *pLast;
char arKey[1];
} Bucket;
typedef struct _hashtable {
uint nTableSize;
uint nTableMask;
uint nNumOfElements;
ulong nNextFreeElement;
Bucket *pInternalPointer;
Bucket *pListHead;
Bucket *pListTail;
Bucket **arBuckets;
dtor_func_t pDestructor;
zend_bool persistent;
unsigned char nApplyCount;
zend_bool bApplyProtection;
} HashTable;
以上のとおり、HashTableは72バイト、Bucketも72バイトあります。続いてPHP 7です。
typedef struct _Bucket {
zval val;
zend_ulong h;
zend_string *key;
} Bucket;
typedef struct _HashTable {
union {
struct {
zend_uchar flags;
zend_uchar nApplyCount;
uint16_t reserve;
} v;
uint32_t flags;
} u;
uint32_t nTableSize;
uint32_t nTableMask;
uint32_t nNumUsed;
uint32_t nNumOfElements;
uint32_t nInternalPointer;
zend_long nNextFreeElement;
Bucket *arData;
uint32_t *arHash;
dtor_func_t pDestructor;
} HashTable;
HashTableは56バイト、Bucketは32バイトに大きく減っています。サイズが少なくなっただけではありません。PHP 7ではzvalの実体をもっているので、動的にzvalを確保することがなく、オーバーヘッドが生じません。さらに、ハッシュテーブルの構造をみてみましょう。
PHP 5ではpListHeadからBucketを動的に確保してチェーンをつないでいましたが、PHP 7ではarDataの先には連続したBucketが確保されています。Bucketを動的に確保することがないので、オーバーヘッドが生じません。ポインタをたどる必要がないので、Bucketを走査する処理も明らかに早くなります。
