php底层HashTable的实现
本文转载自: http://segmentfault.com/blog/tree/1190000000718519
HashTable对PHP来说是一种非常重要的数据结构。很多PHP的内部实现(变量的作用域,函数表,类的属性、方法,数组)就是通过HashTable来实现的。最近了解了一下PHP底层HashTable的实现。
PHP底层HashTable的实现有两个非常重要的结构分别是:HashTable和Bucket。
先说一下HashTable结构:
HashTable的底层实现代码如下:
typedef struct _hashtable{
uint nTableSize; // hash Bucket的大小,最小为8
uint nTableMask; //nTableSize - 1, 索引取值的优化
uint nNumofElements // bucket 里面存的总数
ulong nNextFreeElement //下一个数字索引的位置
Bucket *pInternalPointer //当前遍历的指针(foreach比较快的原因)
Bucket *pListHead //整个hashtable的头指针
Bucket *pListTail //整个hashTable的尾指针
Bucket **argBuckets // Buceket 数组,用来存储数据
doctor_func_t pDestructor //删除元素时的回调函数,用于资源的释放
zend_bool persistent //Bucket的内存分配方式,true使用系统的分配函数,false 使用php的内存分配函数
unsigned char nApplyCount //标记当前hash bucket 被递归的次数
zend_bool bApplyProtection
#if ZEND_DEBUG
int inconsistent
#endif
}HashTable
建议不太了解hash数据结构的同学先简单了解一下hash结构。
简单说一下php中hashtable的初始化操作:
代码如下:
ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, hash_func_t pHashFunction, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC)
{
uint i = 3;
//...
if (nSize >= 0x80000000) {
/* prevent overflow */
ht->nTableSize = 0x80000000;
} else {
while ((1U << i) < nSize) {
i++;
}
ht->nTableSize = 1 << i;
}
// ...
ht->nTableMask = ht->nTableSize - 1;
/* Uses ecalloc() so that Bucket* == NULL */
if (persistent) {
tmp = (Bucket **) calloc(ht->nTableSize, sizeof(Bucket *));
if (!tmp) {
return FAILURE;
}
ht->arBuckets = tmp;
} else {
tmp = (Bucket **) ecalloc_rel(ht->nTableSize, sizeof(Bucket *));
if (tmp) {
ht->arBuckets = tmp;
}
}
return SUCCESS;
}
最开始判断需要初始化的hashtable大小是不是超过了系统能使用的最大大小。下面是对tablesize大小的一个处理。将用户自定义的大小改成需要的大小。例如:如果用户定义的hashtable大小是6,那初始化时,就会将6变成8,如果用户定义的大小为11,那初始化后的Hashtable的大小为16.
下面就是一个简单的判断,来决定是按照C语言本身的分配内存函数来分配内存,还是根据php封装好的内存分配函数来分配内存。
再谈一下 bucket的结构
typedef struct bucket{
ulong h; //对key索引以后的值,数字key不做kash
uint nKeyLength; //key的长度
void *pData;
void *pDataPtr; //指针数据,指向真实数据
struct bucket * pListNext; //整个hash表的下个元素
struct bucket *pListLast; //整个hash表的上个元素
struct bucket *pNext; //本bucket里面,下一个元素
struct bucket *pLast; //本bucket里面的上一个元素
char arKey[1];
}Bucket
这里用一张网络上的很火的图来说明(图原地址没找到,没有做来源说明):
下面是引用了tipi里面的插入说明:
引用地址:tipi
如图中左下角的假设,假设依次插入了Bucket1,Bucket2,Bucket3三个元素:
1、插入Bucket1时,哈希表为空,经过哈希后定位到索引为1的槽位。此时的1槽位只有一个元素Bucket1。 其中Bucket1的pData或者pDataPtr指向的是Bucket1所存储的数据。此时由于没有链接关系。pNext, pLast,pListNext,pListLast指针均为空。同时在HashTable结构体中也保存了整个哈希表的第一个元素指针, 和最后一个元素指针,此时HashTable的pListHead和pListTail指针均指向Bucket1。
2、插入Bucket2时,由于Bucket2的key和Bucket1的key出现冲突,此时将Bucket2放在双链表的前面。 由于Bucket2后插入并置于链表的前端,此时Bucket2.pNext指向Bucket1,由于Bucket2后插入。 Bucket1.pListNext指向Bucket2,这时Bucket2就是哈希表的最后一个元素,这是HashTable.pListTail指向Bucket2。\3、插入Bucket3,该key没有哈希到槽位1,这时Bucket2.pListNext指向Bucket3,因为Bucket3后插入。 同时HashTable.pListTail改为指向Bucket3。
简单来说就是哈希表的Bucket结构维护了哈希表中插入元素的先后顺序,哈希表结构维护了整个哈希表的头和尾。 在操作哈希表的过程中始终保持预算之间的关系。
php底层HashTable的实现的更多相关文章
- PHP内核探索:哈希碰撞攻击是什么?
最近哈希表碰撞攻击(Hashtable collisions as DOS attack)的话题不断被提起,各种语言纷纷中招.本文结合PHP内核源码,聊一聊这种攻击的原理及实现. 哈希表碰撞攻击的基本 ...
- 【转载】网络攻击技术(三)——Denial Of Service & 哈希相关 & PHP语言 & Java语言
找到了这个系列的原始作者: http://www.cnblogs.com/rush/archive/2012/02/05/2339037.html 最近网络安全成了一个焦点,除了国内明文密码的安全事件 ...
- 第 13 章 StringTable详解
目录 第 13 章 StringTable 1.String 的基本特性 1.1.String 概述 1.2.String 的基本特征 1.3.String 的底层结构 2.String 的内存分配 ...
- HashMap和ConcurrentHashMap和HashTable的底层原理与剖析
HashMap 可以允许key为null,value为null,但HashMap的是线程不安全的 HashMap 底层是数组 + 链表的数据结构 在jdk 1.7 中 map集合中的每一项都是一个 ...
- HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别(转)
HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别 文章来源:http://www.cnblogs.com/beatIteWeNerverGiveU ...
- HashTable原理和底层实现
1. 概述 上次讨论了HashMap的结构,原理和实现,本文来对Map家族的另外一个常用集合HashTable进行介绍.HashTable和HashMap两种集合非常相似,经常被各种面试官问到两者的区 ...
- Java 总结 数据底层原理 【包括 ArrayList、LinkedList、hash table、HashMap、Hashtable、ConcurrentHashMap、hash code、HashSet、LinkedHashMap、LinkedHashSet】
1.ArrayList (1)底层是由动态数组实现的[使用了List接口]. (2)动态数组是长度不固定,随着数据的增多而变长. (3)如果不指定,默认长度为10,当添加的元素超过当前数组的长度时,会 ...
- HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别
①HashMap的工作原理 HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象.当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算h ...
- (转)HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别
①HashMap的工作原理 HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象.当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算h ...
随机推荐
- Oracle快速克隆安装
Oracle的家目录进行快速克隆,对同类型机器配置很高效的! 01.确认你在克隆数据库时,原数据库已经关闭 sqlplus / as sysdba; shutdown immediate ; ...
- 在交叉编译中使用最新版的SS
因为旧版本的ss-local总是出现 shake hands failed 错误, 打算用最新的版本试试, 所以尝试在编译中使用最新版的shadowsocks. 项目地址 Shadowsocks-li ...
- C#基础蛋疼到爆的Byte类型表数范围之网兜毛衣见解……
事实上写这篇对Byte类型表数范围的文章,真的是蛋疼+蛋疼+蛋疼,每每看到Byte表数范围这一块.都对-128如此的陌生与迷茫.操蛋的Byte,操蛋的人生-- 熊孩子出场:Byte 恶作剧结果:表数范 ...
- JavaScript-jQuery报TypeError $(...) is null错误(jQuery失效)解决办法
出现这种错误一般都是jQuery的$方法被覆盖, 解决办法: 1.把$改为jQuery使用 jQuery.noConflict();//将变量$的控制权让渡给给其他插件或库 jQuery(functi ...
- nginx error: upstream prematurely closed connection while reading response header from upstream
本篇文章由:http://xinpure.com/nginx-error-upstream-prematurely-closed-connection-while-reading-response-h ...
- HDUOJ---1171
http://acm.hdu.edu.cn/showproblem.php?pid=1171 Big Event in HDU Time Limit: 10000/5000 MS (Java/Othe ...
- Redis下载和安装
原文地址:https://redis.io/download Download Redis uses a standard practice for its versioning: major.min ...
- HDFS配额管理指南
原文地址:http://hadoop.apache.org/docs/r1.0.4/cn/hdfs_quota_admin_guide.html Hadoop分布式文件系统(HDFS)允许管理员为每个 ...
- configure: error: png.h not found.
PHP的时候提示这个错误 configure: error: png.h not found.,这个是选择安装GD模块才会出现的错误,详细错误信息如下 If configure fails try - ...
- Unix环境高级编程(六)进程控制
本章介绍Unix的进程控制,包括进程创建,执行程序和进程终止,进程的属性,exec函数系列,system函数,进程会计机制. 1.进程标识符 每一个进程都有一个非负整数标识的唯一进程ID.ID为0表示 ...