当前位置:首页 > php > 正文内容

php5数组与php7数组区别

phpmianshi3年前 (2018-06-11)php372


PHP5数组结构体

typedef struct _hashtable {  
    uint nTableSize;//4 哈希表中Bucket的槽的数量,初始值为8,每次resize时以2倍速度增长
    uint nTableMask;//4   nTableSize-1 , 索引取值的优化
    uint nNumOfElements;//4  哈希表中Bucket中当前存在的元素个数,count()函数会直接返回此值
    ulong nNextFreeElement;//4  下一个数字索引的位置
    Bucket *pInternalPointer;   /* Used for element traversal 4*/  当前遍历的指针(foreach比for快的原因之一) 用于元素遍历
    Bucket *pListHead;//4  存储数组头元素指针
    Bucket *pListTail;//4  存储数组尾元素指针
    Bucket **arBuckets;//4  //指针数组,数组中每个元素都是指针 存储hash数组
    dtor_func_t pDestructor;//4   在删除元素时执行的回调函数,用于资源的释放 /* persistent 指出了Bucket内存分配的方式。如果persisient为TRUE,则使用操作系统本身的内存分配函数为Bucket分配内存,否则使用PHP的内存分配函数。*/
    zend_bool persistent;//1  
    unsigned char nApplyCount;//1  标记当前hash Bucket被递归访问的次数(防止多次递归)
    zend_bool bApplyProtection;//1  标记当前hash桶允许不允许多次访问,不允许时,最多只能递归3次
#if ZEND_DEBUG  
    int inconsistent;//4  
#endif  
} HashTable; 

typedef struct bucket {  
    ulong h;    /* Used for numeric indexing                4字节 */  对char *key进行hash后的值,或者是用户指定的数字索引值/* Used for numeric indexing */
    uint nKeyLength;    /* The length of the key (for string keys)  4字节 字符串索引长度,如果是数字索引,则值为0 */  
    void *pData;        /* 4字节 实际数据的存储地址,指向value,一般是用户数据的副本,如果是指针数据,则指向pDataPtr*/  //这里又是个指针,zval存放在别的地方
    void *pDataPtr;         /* 4字节 引用数据的存储地址,如果是指针数据,此值会指向真正的value,同时上面pData会指向此值 */  
    struct bucket *pListNext;  /* PHP arrays are ordered. This gives the next element in that order4字节 整个哈希表的该元素的下一个元素*/  
    struct bucket *pListLast;  /* and this gives the previous element           4字节 整个哈希表的该元素的上一个元素*/  
    struct bucket *pNext;      /* The next element in this (doubly) linked list     4字节 同一个槽,双向链表的下一个元素的地址 */  
    struct bucket *pLast;      /* The previous element in this (doubly) linked list     4字节 同一个槽,双向链表的上一个元素的地址*/  
    char arKey[1];            /* Must be last element   1字节 保存当前值所对于的key字符串,这个字段只能定义在最后,实现变长结构体*/  
} Bucket;

image.png

这个图看起来很复杂,各种指针跳来跳去,当我们通过key值访问一个元素内容的时候,有时需要3次的指针跳跃才能找对需要的内容。而最重要的一点,就在于这些数组元素存储,都是分散在各个不同的内存区域的。同理可得,在CPU读取的时候,因为它们就很可能不在同一级缓存中,会导致CPU不得不到下级缓存甚至内存区域查找,也就是引起CPU缓存命中下降,进而增加更多的耗时。


PHP7数组结构体

typedef struct _HashTable { 
    union {
        struct {
            ZEND_ENDIAN_LOHI_3(
                zend_uchar    flags,
                zend_uchar    nApplyCount,  /* 循环遍历保护 */
                uint16_t      reserve)
        } v;
        uint32_t flags;
    } u;
    uint32_t          nTableSize;           /* hash表的大小 HashTable的大小,始终为2的指数(8,16,32,64...)。最小为8,最大值根据机器不同而不同*/
    uint32_t          nTableMask;           /* 掩码,用于根据hash值计算存储位置,永远等于nTableSize-1 */
    uint32_t          nNumUsed;             /* arData数组已经使用的数量 */
    uint32_t          nNumOfElements;       /* hash表中元素个数 */
    uint32_t          nInternalPointer;     /* 用于HashTable遍历 */
    zend_long         nNextFreeElement; /* 下一个空闲可用位置的数字索引 */
    Bucket           *arData;               /* 存放实际数据 */
    uint32_t         *arHash;               /* Hash表 */
    dtor_func_t       pDestructor;          /* 析构函数 */
} HashTable;

typedef struct _Bucket {
    zval              val;  
    zend_ulong        h;                /* hash value (or numeric index)   */
    zend_string      *key;              /* string key or NULL for numerics */
} Bucket;

image.png

新版本的数组结构,整块的数组元素和hash映射表全部连接在一起,被分配在同一块内存内。如果是遍历一个整型的简单类型数组,效率会非常快,因为,数组元素(Bucket)本身是连续分配在同一块内存里,并且,数组元素的zval会把整型元素存储在内部,也不再有指针外链,全部数据都存储在当前内存区域内。当然,最重要的是,它能够避免CPU Cache Miss(CPU缓存命中率下降)。


Zend Array的变化:

  1. 数组的value默认为zval。

  2. HashTable的大小从72下降到56字节,减少22%。

  3. Buckets的大小从72下降到32字节,减少50%。

  4. 数组元素的Buckets的内存空间是一同分配的。

  5. 数组元素的key(Bucket.key)指向zend_string。

  6. 数组元素的value被嵌入到Bucket中。

  7. 降低CPU Cache Miss。



版权声明:本文由PHP面试资料网发布,如需转载请注明出处。
分享给朋友:

相关文章

PHP数组实际占用内存大小的分析

1.数组正常的赋值是不会发生内存改变的,但是当赋值的新数组发生改动的时候,php就会新开辟内存给新的数组,这里会造成无谓的内存消耗。最好是不要直接这样赋值,如果非赋值不可的话,记得加上‘&’符...

PHP红包分配算法

<?php /**  * User: phpmianshi.com   * Date: 2020/3/31 &nbs...

PHP内核分析之源码目录结构 (二)

一、目录概览以php-7.4.1为例,目录多达十多个,下面介绍主要目录。├── build   linux下编译相关的目录├── ext      P...

PHP7的垃圾回收机制

PHP7的垃圾回收机制

垃圾回收机制垃圾回收机制是一种动态存储分配方案。它会自动释放程序不再需要的已分配的内存块。 自动回收内存的过程叫垃圾收集。垃圾回收机制可以让程序员不必过分关心程序内存分配,从而将更多的精力投入到业务逻...

php-fpm的优雅重启关闭

PHP 5.3.3 下的php-fpm 不再支持 php-fpm 以前具有的 /usr/local/php/sbin/php-fpm (start|stop|reload)等命令,需要使用信号控制:m...

记一次tp3.2.3因fetch导致的漏洞处理过程

记一次tp3.2.3因fetch导致的漏洞处理过程

问题描述:最近发现百度收录大幅度下降,并出现大量5xx错误,有些收录页面直接跳转到其他网站,如下图:问题追查1.根据以往经验首先怀疑网站被植入或者挂马      &nbs...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。