PHP中的哈希表结构的详细说明
哈希表是Zend引擎的最重要和最广泛使用的数据结构,用于存储几乎一切。1.2.1数据结构
哈希表的数据结构定义如下:
复制代码代码如下所示:
typedef struct斗{
页H / /存储散列;
单位nkeylength;
void * pData; / /指针的值,是一份用户数据
void * pdataptr;
结构斗* plistnext; / / plistnext和plistlast。
结构斗* plistlast; / /双链表,哈希表
结构斗* pnext;一个散列 / / pnext和塑料
结构斗*塑料; / /双链表
字符都可以实现{ 1 }; / /关键
桶};
_hashtable { typedef struct
单位ntablesize;
Uint nTableMask;
单位nnumofelements;
nnextfreeelement页;
斗* pinternalpointer用于元素遍历; / * * /
plisthead斗*;
plisttail斗*;
斗* arbuckets; / /哈希数组
dtor_func_t pdestructor; / /指定的哈希表的初始化,叫斗的破坏
zend_bool执着; / /内存分配程序是否使用C
unsigned char napplycount;
zend_bool bapplyprotection;
如果zend_debug #
int一致;
# endif
哈希表};
总的来说,Zend的哈希表是一个哈希链也是线性遍历优化,这说明如下:
哈希表包含两个数据结构,一个列表的哈希和双链表。前者用于快速键值查询,便于线性遍历和排序,在两种数据结构中都存在一个桶。
对数据结构的几种解释:
为什么在链散列中使用双向链表
一般的哈希链只需要操作的关键,只有单链表是必要的。然而,Zend有时需要从链表中删除一个给定哈希桶,和一个双链表的使用可以非常有效的。
ntablemask做什么
这个值是使用的哈希值转换为arbuckets数组下标。初始化哈希表时,Zend首先将ntablesize大小的内存arbuckets阵列,和ntablesize不小于最小的2 ^ n由用户指定,即二进制的10。ntablemask = ntablesize u2013 1,即二进制的01 *,当H ntablemask正好落在{ 0,1 } ntablesize u2013,Zend使用它作为访问arbuckets数组索引。
pdataptr做什么
通常情况下,用户插入一个键值对的时候,Zend拷贝一份价值点的数据到一个值复制。复制操作需要调用Zend内部常规emalloc分配内存,这是一个非常耗时的操作和消耗比价值更大的内存。(如果更多的内存用于存储cookie),如果值很小,这将导致更大的浪费。考虑到HashTable主要是用来存储指针的值,或者引入pdataptr。当价值是只要一个指针,它直接pdataptr Zend的副本,和点数据来pdataptr。这避免了emalloc操作,也有助于提高缓存命中率。
为什么是大小都可以实现只有1为什么不使用指针来管理密钥呢
ArKey是关键的一个数组,但其规模仅为1,不足以放下的关键。下面的代码可以在初始化函数找到HashTable:
复制代码代码如下所示:
P =(桶*)pemalloc(sizeof(桶)- 1 + nkeylength,HT ->持续);
可以看出,Zend分配一桶减少本身和关键记忆,上部斗,下部是关键,并且都可以实现只是斗的最后一个元素都可以实现,因此可以用来访问的关键。这种技术在内存管理程序是最常见的,而分配内存,是实际分配的内存超过指定大小,上部常被称为cookie,存储记忆的信息,如块的大小,一个指针,指针。百度用这种方法传输程序。
没有指针用于管理密钥,减少emalloc操作,同时也增加了缓存的命中率。另一个重要的原因是,关键是固定的,并不会重新分配整个斗因为更长时间的关键。这也解释了为什么价值分配不在一起为一个阵列,因为价值变量。
1.2.2 PHP数组
还有一个问题关于哈希表,没有回答,那就是,nnextfreeelement是做什么的
Unlike general hash, Zend's HashTable allows users to specify hash values directly, ignoring key, or even key (at this time, nKeyLength is 0).At the same time, HashTable also supports append operation. 用户不需要指定散列值。他们只需要提供价值。在这个时候,Zend采用nnextfreeelement作为哈希,然后nnextfreeelement增加。
Hashtable这种行为看起来很奇怪,因为它不能够通过密钥访问的价值,它不是一个哈希完全,对问题的理解的关键是,PHP数组是使用哈希表-关联数组使用哈希表实现正常的元素为K-V映射,用户指定的键字符串;非联想数组作为数组索引的哈希值,关键是不存在的;与相关和非相关混合阵列时,或使用array_push操作,你需要使用nnextfreeelement。
再看价值。PHP数组的值直接使用机制的通用结构。数据是指zval *。根据上一节的介绍,zval *将直接存储在pdataptr。因为机制直接使用,该数组的元素可以是任意PHP类型。
该阵列,即每个,每个,等遍历操作,通过一个双向链表,哈希表进行的,pinternalpointer光标的当前位置作为记录。
1.2.3变量符号表
除了阵列,HashTable也用来储存大量的其他数据,如PHP函数,变量符号,加载的模块、类成员,等等。
变量符号表等效于关联数组。它的关键是变量名。(可见,用一个很长的变量名是不是一个好主意),价值机制*。
在任何一个时间的PHP代码,可以看到两个变量:symbol_table和active_symbol_table:符号表用于存储全局变量,称为全局符号表;后者是一个指针变量的符号表的当前活动,通常是全局符号表。然而,当进入一个PHP函数的时候,它是指利用PHP代码的用户创建的功能。Zend将创造和点active_symbol_table的局部符号表函数的局部变量符号表。Zend总是用active_symbol_table访问变量,从而实现局部变量的范围控制。
然而,如果函数的本地访问标记为全局变量,可以将做特殊处理,创造symbol_table在active_symbol_table在相同名称的变量的引用,如果在symbol_table没有命名空间变量,它将创造第一。
1.3内存和文件
程序拥有的资源通常包括内存和文件。对于正常程序,这些资源是面向过程的。当过程完成时,操作系统或C库将自动回收我们未显式释放的资源。
然而,PHP程序有其特殊性。它是基于页面的。当页面运行时,它也将应用于内存或文件等资源。然而,当页面运行时,操作系统或C库可能不知道它所需要的资源回收。例如,我们PHP编译成模块和运行在Apache prefork模式Apache或工人。在这种情况下,Apache进程或线程是可重复使用,并通过PHP页面分配的内存将保留在记忆中直到核心。
为了解决这个问题,可以提供一组内存分配API,它的功能就像C的相应功能。不同的是,这些函数分配内存,从Zend自己的内存池,可以实现基于页面的自动恢复。在我们的模块,分配的内存页面应该使用这些API而不是C例程。否则,Zend将饱和在页末我们的记忆力下降,结果通常是粉碎。
Emalloc()
依芙利特()
Estrdup()
Estrndup()
Ecalloc()
Erealloc()
此外,Zend还提供了一组宏,如vcwd_xxx,取代C库和相应的API操作系统。这些宏可以支持PHP的虚拟目录,他们应该使用模块代码。该宏的具体定义称为PHP源码TSRM / tsrm_virtual_cwd.h.maybe你会发现所有的宏不提供关闭操作,这是因为接近的对象是开放的资源,对文件路径不相关,那么你可以直接使用C或读/写操作系统例程;同样,这样的操作也是直接使用C或操作系统例程。