File tree Expand file tree Collapse file tree 5 files changed +8
-8
lines changed
Expand file tree Collapse file tree 5 files changed +8
-8
lines changed Original file line number Diff line number Diff line change @@ -38,7 +38,7 @@ struct _zend_array {
3838 dtor_func_t pDestructor;
3939};
4040```
41- HashTable中有两个非常相近的值:` nNumUsed ` 、` nNumOfElements ` ,` nNumOfElements ` 表示哈希表已有元素数,那这个值不跟` nNumUsed ` 一样吗?为什么要定义两个呢?实际上它们有不同的含义,当将一个元素从哈希表删除时并不会将对应的Bucket移除,而是将Bucket存储的zval标示为 ` IS_UNDEF ` ,只有扩容时发现nNumOfElements与nNumUsed相差达到一定数量(这个数量是:` ht->nNumUsed - ht->nNumOfElements > (ht->nNumOfElements >> 5) ` )时才会将已删除的元素全部移除,重新构建哈希表。所以` nNumUsed ` >=` nNumOfElements ` 。
41+ HashTable中有两个非常相近的值:` nNumUsed ` 、` nNumOfElements ` ,` nNumOfElements ` 表示哈希表已有元素数,那这个值不跟` nNumUsed ` 一样吗?为什么要定义两个呢?实际上它们有不同的含义,当将一个元素从哈希表删除时并不会将对应的Bucket移除,而是将Bucket存储的zval修改为 ` IS_UNDEF ` ,只有扩容时发现nNumOfElements与nNumUsed相差达到一定数量(这个数量是:` ht->nNumUsed - ht->nNumOfElements > (ht->nNumOfElements >> 5) ` )时才会将已删除的元素全部移除,重新构建哈希表。所以` nNumUsed ` >=` nNumOfElements ` 。
4242
4343HashTable中另外一个非常重要的值` arData ` ,这个值指向存储元素数组的第一个Bucket,插入元素时按顺序 __ 依次插入__ 数组,比如第一个元素在arData[ 0] 、第二个在arData[ 1] ...arData[ nNumUsed] 。PHP数组的有序性正是通过` arData ` 保证的,这是第一个与普通散列表实现不同的地方。
4444
@@ -155,7 +155,7 @@ static void ZEND_FASTCALL zend_hash_do_resize(HashTable *ht)
155155```
156156
157157### 2.2.6 重建散列表
158- 当删除元素达到一定数量或扩容后都需要重建散列表,因为value在Bucket位置移动了或哈希数组nTableSize变化了导致key与value的映射关系改变,重建过程实际就是遍历Bucket数组中的value,然后重新计算映射值更新到散列表,除了更新散列表之外,这里还有一个重要的处理:移除已删除的value,开始的时候我们说过,删除value时只是将value的type表为了IS_UNDEF ,并没有实际从Bucket数组中删除,如果这些value一直存在那么将浪费很多空间,所以这里会把它们移除,操作的方式也比较简单:将后面未删除的value依次前移,具体过程如下:
158+ 当删除元素达到一定数量或扩容后都需要重建散列表,因为value在Bucket位置移动了或哈希数组nTableSize变化了导致key与value的映射关系改变,重建过程实际就是遍历Bucket数组中的value,然后重新计算映射值更新到散列表,除了更新散列表之外,这里还有一个重要的处理:移除已删除的value,开始的时候我们说过,删除value时只是将value的type设置为IS_UNDEF ,并没有实际从Bucket数组中删除,如果这些value一直存在那么将浪费很多空间,所以这里会把它们移除,操作的方式也比较简单:将后面未删除的value依次前移,具体过程如下:
159159```c
160160//zend_hash.c
161161ZEND_API int ZEND_FASTCALL zend_hash_rehash(HashTable *ht)
Original file line number Diff line number Diff line change @@ -60,7 +60,7 @@ struct _zval_struct {
6060};
6161```
6262` zval ` 结构比较简单,内嵌一个union类型的` zend_value ` 保存具体变量类型的值或指针,` zval ` 中还有两个union:` u1 ` 、` u2 ` :
63- * __ u1:__ 它的意义比较直观,变量的类型就通过` u1.type ` 区分,另外一个值` type_flags ` 为类型掩码,在变量的内存管理、gc机制中会用到,第三部分会详细分析,至于后面两个` const_flags ` 、` reserved ` 暂且不管
63+ * __ u1:__ 它的意义比较直观,变量的类型就通过` u1.v. type ` 区分,另外一个值` type_flags ` 为类型掩码,在变量的内存管理、gc机制中会用到,第三部分会详细分析,至于后面两个` const_flags ` 、` reserved ` 暂且不管
6464* __ u2:__ 这个值纯粹是个辅助值,假如` zval ` 只有:` value ` 、` u1 ` 两个值,整个zval的大小也会对齐到16byte,既然不管有没有u2大小都是16byte,把多余的4byte拿出来用于一些特殊用途还是很划算的,比如next在哈希表解决哈希冲突时会用到,还有fe_pos在foreach会用到......
6565
6666从` zend_value ` 可以看出,除` long ` 、` double ` 类型直接存储值外,其它类型都为指针,指向各自的结构。
Original file line number Diff line number Diff line change @@ -245,7 +245,7 @@ int main()
245245 return 0;
246246}
247247```
248- 我们知道name的值分配在栈上 ,而" pangudashu" 分配在常量区,那么" name" 变量名分配在哪呢?
248+ 我们知道指针name分配在栈上 ,而" pangudashu" 分配在常量区,那么" name" 变量名分配在哪呢?
249249
250250实际上C里面是不会存变量名称的,编译的过程会将变量名替换为偏移量表示:`ebp - 偏移量`或`esp + 偏移量`,将上面的代码转为汇编:
251251```c
@@ -272,7 +272,7 @@ main:
272272
273273![ php vs c] ( ../img/php_vs_c.png )
274274
275- 在编译时就可确定且不会改变的量称为字面量,也称作常量(IS_CONST),这些值在编译阶段就已经分配zval,保存在` zend_op_array->literals ` 数组中(对应c程序的常量内存区 ),访问时通过` _zend_op_array->literals + 偏移量 ` 读取,举个例子:
275+ 在编译时就可确定且不会改变的量称为字面量,也称作常量(IS_CONST),这些值在编译阶段就已经分配zval,保存在` zend_op_array->literals ` 数组中(对应c程序的常量存储区 ),访问时通过` _zend_op_array->literals + 偏移量 ` 读取,举个例子:
276276``` c
277277<?php
278278$a = 56 ;
@@ -372,11 +372,11 @@ void zend_compile_stmt(zend_ast *ast)
372372 switch (ast->kind) {
373373 case xxx:
374374 ...
375- break;
375+ break;
376376 case ZEND_AST_ECHO:
377377 zend_compile_echo(ast);
378378 break;
379- ...
379+ ...
380380 default:
381381 {
382382 znode result;
Original file line number Diff line number Diff line change @@ -94,7 +94,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HAN
9494
9595
9696
97- > 注意:这里include文件中定义的var_1实际是替换了原文件中的变量,也就是只有一个var_1 ,所以此处zend_array的引用是1而不是2
97+ > 注意:这里include文件中定义的var_2实际是替换了原文件中的变量,也就是只有一个var_2 ,所以此处zend_array的引用是1而不是2
9898
9999接下来就是被包含文件的执行,执行到`$var_2 = array()`时,将原array(1,2,3)引用减1变为0,这时候将其释放,然后将新的value:array()赋给$var_2,这个过程就是普通变量的赋值过程,注意此时调用文件中的$var_2仍然指向被释放掉的value,此时的内存关系:
100100
File renamed without changes.
You can’t perform that action at this time.
0 commit comments