欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

php 内存分配和管理

程序员文章站 2022-03-24 13:36:42
...
                            
zend解析 php 变量的赋值操作


前提。我们需要知道php 的内核zend:
       Zend整体用纯c实现,是php的内核部分,它将php代码翻译(词法、语法解析等一系列编译过程)为可执行opcode的处理并实现相应的处理方法、实现了基本的数据结构(如hashtable、oo)、内存分配及管理、提供了相应的api方法供外部调用,是一切的核心,所有的外围功能均围绕zend实现。
      那么我们说到的内存分配和管理,自然是由zend 来完成的,那么zend 是如何针对变量进行内存分配和管理的呢?



zend 中对变量的声明:
struct _zval_struct {
    zvalue_value value; /* 变量的值 */
    zend_uint refcount__gc;  /*符号表中 变量名的个数*/
    zend_uchar type;    /* 变量当前的数据类型 */
    zend_uchar is_ref__gc; /**/
};
typedef struct _zval_struct zval;



一: 变量的简单赋值操作。


看一段php 代码
<?php 
     $a = "xxxx";
     $b = $a;
     $b = "yyy";// 或者 unset($a);
?>


在这里,第一步  $a="xxxx";  
     $a的值 字符串“xxxx” 保存在毫不相关的结构体zval 中的 value 项。 而变量的名称$a 则是通过 zend 的方法    zend_hash_add把它添加到符号表里。即:也就是将zval的指针的变量存放在了符号表中。这样才能用$a 访问到 “xxxx”。  这个时候,只有$a 指向 zval  所以 refcount=1.

下面是 一个zend 的源码 对赋值操作的解释:


{
    zval *fooval;
    MAKE_STD_ZVAL(fooval);
    ZVAL_STRING(fooval, "xxxx", 1);
    ZEND_SET_SYMBOL( EG(active_symbol_table) ,  "a" , fooval);
}       

首先,我们声明一个zval指针,并申请一块内存。然后通过ZVAL_STRING宏将值设置为‘xxxx’,最后一行的作用就是将这个zval加入到当前的符号表里去,并将其label定义成a,这样用户就可以在代码里通过$a来使用它了。

第二步  $b = $a ;
     将$a赋值给$b ,zend 方法 zend_hash_add把变量名称 zval指针的变量$b 添加到符号表里。  通过结构体zval 达到共享。 从而节省了内存。也就是:符号表中b也是存放的zval指针变量。   符号表中 a  b 对应同一个zval指针的地址   所以refcount=2


假如说 第三步操作 是   unset($a);
释放$a的值 zval 中的value。 那么是不是$b 的值也就不存在了?
   
   其实不是这样的,在结构体zval 中有一个属性  refcount . 它会处理掉这样的问题。

refcount  : 当变量被创建并且赋值的时候,在符号表中变量 a 通过zval指针 和内存中zval结构体建立联系,这个时候refcount=1  ,当$b=$a.的时候,也就是变量名称b 也是通过zval指针 和内存中zval结构体建立联系,这个时候 refcount=2.,所以unset只需把这个zval的refcount减去1就行了!结果就是 只有 符号表中的b 通过zval类型的指针 和 zval(存放字符串的zval结构体)建立联系 。
  
假如说 第三步操作是 $b="yyy";
结果肯定是$b 和 $a 各有一个值。当执行赋值的时候,也就是要改变变量$b的值的时候,他们就不能共享zval 了。zend 会判断zval 中的refcount 是否大于1,大于1的话。 这个时候zend 会复制一个的zval 来 存储b  , 并且重新定义符号表中的b ,新建一个新的zval指针 指向新的zval


以上是我对变量 在php内存分配的理解。哪里不对  希望大家指出

未完待续。

二:zend 引用变量的赋值