php 内存分配和管理

阅读更多
                            
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 代码



在这里,第一步  $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 引用变量的赋值









 

你可能感兴趣的:(php内核,php内存分配,php内存管理,zend,php)