深入理解PHP内核之HashTable(一)

栏目: IT技术 · 发布时间: 4年前

内容简介:之前的俩篇文章对于PHP内核一直有关注的同学, 应该对PHP5的Hashtable会比较熟悉, 但我们还是先来简单回顾一下PHP5的Hashtable:

之前的俩篇文章 深入理解 PHP 7内核之zval 和 深入理解PHP7内核之Reference , 我介绍了我们在开发PHP7的时候对zval和reference的一些改造思考和结果, 之后因为确实精力有限就没有继续往下写,时隔一年多以后,因为这场突如其来的疫情,在家办公的时间很多, 于是终于有了时间让我来继续介绍一下PHP7的中Hashtable的变化, 以及当时我们做这些变化背后的考量.

PHP5的Hashtable

对于PHP内核一直有关注的同学, 应该对PHP5的Hashtable会比较熟悉, 但我们还是先来简单回顾一下PHP5的Hashtable:

深入理解PHP内核之HashTable(一)

在PHP5的实现中, Hashtable的核心是存储了一个个指向zval指针的指针, 也就是zval**(我遇到不少的同学问为什么是zval**, 而不是zval*, 这个原因其实很简单, 因为Hashtable中的多个位置都可能指向同一个zval, 那么最常见的一个可能就是在COW的时候, 当我们需要把一个变量指向一个新的zval的时候, 如果在符号表中存的是zval*, 那们我们就做不到对一处修改, 所有的持有方都有感知, 所以必须是zval**), 这样的设计在最初的出发点是为了让Hashtable可以存储任何尺寸的任何信息, 不仅仅是指针, 还可以存储一段内存值(当然实际上大部分情况下,比如符号表还是存的zval的指针).

PHP5的代码中也用了比较Hack的方式来判断存储的是什么:

#define UPDATE_DATA(ht, p, pData, nDataSize)                                            \
    if (nDataSize == sizeof(void*)) {                                                   \
        if ((p)->pData != &(p)->pDataPtr) {                                             \
            pefree_rel((p)->pData, (ht)->persistent);                                   \
        }                                                                               \
        memcpy(&(p)->pDataPtr, pData, sizeof(void *));                                  \
        (p)->pData = &(p)->pDataPtr;                                                    \
    } else {                                                                            \
        if ((p)->pData == &(p)->pDataPtr) {                                             \
            (p)->pData = (void *) pemalloc_rel(nDataSize, (ht)->persistent);            \
            (p)->pDataPtr=NULL;                                                         \
        } else {                                                                        \
            (p)->pData = (void *) perealloc_rel((p)->pData, nDataSize, (ht)->persistent);   \
            /* (p)->pDataPtr is already NULL so no need to initialize it */             \
        }                                                                               \
        memcpy((p)->pData, pData, nDataSize);                                           \
    }

它来判断存储的size是不是一个指针大小, 从而采用不同的方式来更新存储的内容。非常Hack的方式。

PHP5的Hashtable对于每一个Bucket都是分开申请释放的。

而存储在Hashtable中的数据是也会通过pListNext指针串成一个list,可以直接遍历,关于这块可以参看我很早的一篇文章深入理解PHP之数组

问题

在写PHP7的时候,我们详细思考了几点可能优化的点,包括也从性能角度总结了以下目前这种实现的几个问题:

1. Hashtable在PHP中,应用最多的是保存各种zval, 而PHP5的HashTable设计的太通用,可以设计为专门为了存储zval而优化

2. 缓存局部性问题, 因为PHP5的Hashtable的Bucket,包括zval都是独立分配的,并且采用了List来串Hashtable中的所有元素,会导致在遍历或者顺序访问一个数组的时候,缓存不友好

3. 和1类似,在PHP5的Hashtable中,要访问一个zval,因为是zval**, 那需要至少解指针俩次,一方面是缓存不友好,另外一方面也是效率低下。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

史玉柱自述

史玉柱自述

优米网 / 同心出版社 / 2013-6-1 / 42.00元

史玉柱迄今为止唯一公开著作。 亲口讲述24年创业历程与营销心得。 中国商业思想史里程碑之作! 24年跌宕起伏,功成身退,史玉柱向您娓娓道来,历经时间沉淀的商业智慧和人生感悟。 在书中,史玉柱毫无保留地回顾了创业以来的经历和各阶段的思考。全书没有深奥的理论,铅华洗尽、朴实无华,往往在轻描淡写之间,一语道破营销的本质。 关于产品开发、营销传播、广告投放、团队管理、创业投资......一起来看看 《史玉柱自述》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具