HashTable定义给出:
typedef struct _hashtable {
uint nTableSize; //表长度,并非元素个数
uint nTableMask;//表的掩码,始终等于nTableSize-1
uint nNumOfElements;//存储的元素个数
ulong nNextFreeElement;//指向下一个空的元素位置
Bucket *pInternalPointer;//foreach循环时,用来记录当前遍历到的元素位置
Bucket *pListHead;
Bucket *pListTail;
Bucket **arBuckets;//存储的元素数组
dtor_func_t pDestructor;//析构函数
zend_bool persistent;//是否持久保存。从这可以发现,PHP数组是可以实现持久保存在内存中的,而无需每次请求都重新加载。
unsigned char nApplyCount;
zend_bool bApplyProtection;
} HashTable;
除了几个记录table大小,所含元素数量的属性变量外,Bucket被多次使用到,Bucket是如何定义的:
typedef struct bucket {
ulong h; //数组索引
uint nKeyLength; //字符串索引的长度
void *pData; //实际数据的存储地址
void *pDataPtr; //引入的数据存储地址
struct bucket *pListNext;
struct bucket *pListLast;
struct bucket *pNext; //双向链表的下一个元素的地址
struct bucket *pLast;//双向链表的下一个元素地址
char arKey[1]; /* Must be last element */
} Bucket;
有点像一个链表,Bucket就像是一个链表节点,有具体的数据和指针,而HashTable就是一个array,保存着一串Bucket元素。PHP中多维数组的实现,不过就是Bucket里面存着另一个HashTable罢了。
算一算HashTable需要占用39个字节,Bucket需要33个字节。一个空的数组就需要占用14 + 39 + 33 = 86个字节。Bucket 结构需要 33 个字节,键长超过四个字节的部分附加在 Bucket 后面,而元素值很可能是一个 zval 结构,另外每个数组会分配一个由 arBuckets 指向的 Bucket 指针数组, 虽然不能说每增加一个元素就需要一个指针,但是实际情况可能更糟。这么算来一个数组元素就会占用 54 个字节,与上面的估算几乎一样。
从空间的角度来看,小型数组平均代价较大,当然一个脚本中不会充斥数量很大的小型数组,可以以较小的空间代价来获取编程上的快捷。但如果将数组当作容器来使用就是另一番景象了,实际应用经常会遇到多维数组,而且元素居多。比如10k个元素的一维数组大概消耗540k内存,而10k x 10 的二维数组理论上只需要 6M 左右的空间,但是按照 memory_get_usage 的结果则两倍于此,[10k,5,2]的三维数组居然消耗了23M,小型数组确实是划不来的。
PHP数组内存利用率低的原因,讲到这里,接下来的文章将解读PHP数组操作的具体实现。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持易采站长站。







