PHP 数组的底层实现使用了 HashTable 这种数据结构,PHP 7.0 相比于旧版本 PHP 数组做了很多的修改,本文主要记录 PHP7.0 相对于旧版本修改了那些东西。

介绍 PHP7 HashTable

HasahTable 又叫做散列表,具有如下特点(具体可参考《数据结构与算法分析》第五章散列)

  • 可以以 O(1) 的效率执行数据插入、删除和查找操作
  • 通过散列函数维护 K-V 之间的映射关系,可能会产生哈希冲突现象等
  • 数据是 K-V 形式存储,元素间是无顺序的结构,不能对数据进行排序

PHP7 优化介绍

PHP 5 到 PHP 7.0 HashTable 主要做了如下修改

  • 优化 HashTable 的数据结构:一个 PHP 数组 zend_array 的内存占用从PHP5点72个字节,降低到了56个字节
  • 使用内存缓存局部性的特点,优化 PHP 数组效率
    • PHP 5 的 Bucket ,包括 zval 都是独立分配(在内存中是离散的)
    • PHP 7 中使用一块连续的空间存储  Bucket,并且一个 Bucket 中包含一个 zval 数据,即 Bucket 和 zval 在内存中都是连续存储的
  • 其他一些细节优化
    • 指针访问速度
    • 优化 Empty Array
    • .......

PHP 5 HashTable 的数据结构

typedef struct _hashtable {
    uint nTableSize;        /* 散列表大小, Hash值的区间 */
    uint nTableMask;        /* 等于nTableSize -1, 用于快速定位 */
    uint nNumOfElements;    /* HashTable中实际元素的个数 */
    ulong nNextFreeElement; /* 下个空闲可用位置的数字索引 */
    Bucket *pInternalPointer;   /* 内部位置指针, 会被reset, current这些遍历函数使用 */
    Bucket *pListHead;      /* 头元素, 用于线性遍历 */
    Bucket *pListTail;      /* 尾元素, 用于线性遍历 */
    Bucket **arBuckets;     /* 实际的存储容器 */
    dtor_func_t pDestructor;/* 元素的析构函数(指针) */
    zend_bool persistent;
    unsigned char nApplyCount; /* 循环遍历保护 */
    zend_bool bApplyProtection;
    #if ZEND_DEBUG
    int inconsistent;
    #endif
} HashTable;

typedef struct bucket {
    ulong h;                        /* 数字索引/hash值 */
    uint nKeyLength;                /* 字符索引的长度 */
    void *pData;                    /* 数据 */
    void *pDataPtr;                 /* 数据指针 */
    struct bucket *pListNext;               /* 下一个元素, 用于线性遍历 */
    struct bucket *pListLast;       /* 上一个元素, 用于线性遍历 */
    struct bucket *pNext;                   /* 处于同一个拉链中的下一个元素 */
    struct bucket *pLast;                   /* 处于同一拉链中的上一个元素 */
    char arKey[1]; /* 节省内存,方便初始化的技巧 */
} Bucket;
PHP 5 HashTable 数据结构

相关文章:

  • 2021-12-02
  • 2022-12-23
  • 2021-06-17
  • 2022-12-23
  • 2021-12-20
  • 2021-09-13
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2021-12-02
  • 2021-12-26
  • 2022-02-01
  • 2021-07-21
  • 2021-07-11
相关资源
相似解决方案