• 《PHP


    本文总结自:

      《PHP7 内核剖析 - 变量的内部实现》

    一:变量的实现

      - 变量是一个语言实现的基础

      - 在PHP中,变量的组成部分为 变量名(zval) 变量值(zend_value)

      - zval结构比较简单,内嵌一个union类型的zend_value保存具体变量类型的值或指针

    • //zend_types.h
      typedef struct _zval_struct     zval;
      
      typedef union _zend_value {
          zend_long         lval;    //int整形
          double            dval;    //浮点型
          zend_refcounted  *counted;
          zend_string      *str;     //string字符串
          zend_array       *arr;     //array数组
          zend_object      *obj;     //object对象
          zend_resource    *res;     //resource资源类型
          zend_reference   *ref;     //引用类型,通过&$var_name定义的
          zend_ast_ref     *ast;     //下面几个都是内核使用的value
          zval             *zv;
          void             *ptr;
          zend_class_entry *ce;
          zend_function    *func;
          struct {
              uint32_t w1;
              uint32_t w2;
          } ww;
      } zend_value;
      
      struct _zval_struct {
          zend_value        value; //变量实际的value
          union {
              struct {
                  ZEND_ENDIAN_LOHI_4( //这个是为了兼容大小字节序,小字节序就是下面的顺序,大字节序则下面4个顺序翻转
                      zend_uchar    type,         //变量类型
                      zend_uchar    type_flags,  //类型掩码,不同的类型会有不同的几种属性,内存管理会用到
                      zend_uchar    const_flags,
                      zend_uchar    reserved)     //call info,zend执行流程会用到
              } v;
              uint32_t type_info; //上面4个值的组合值,可以直接根据type_info取到4个对应位置的值
          } u1;
          union {
              uint32_t     var_flags;
              uint32_t     next;                 //哈希表中解决哈希冲突时用到
              uint32_t     cache_slot;           /* literal cache slot */
              uint32_t     lineno;               /* line number (for ast nodes) */
              uint32_t     num_args;             /* arguments number for EX(This) */
              uint32_t     fe_pos;               /* foreach position */
              uint32_t     fe_iter_idx;          /* foreach iterator index */
          } u2; //一些辅助值
      };

    二:内存管理

      - 由于硬拷贝的效率太低

      - 所以PHP的变量管理是通过 引用计数,写时复制

    三: 引用计数

      - 引用计数是指在value中增加一个字段refcount记录指向当前value的数量

      - 变量复制、函数传参时并不直接硬拷贝一份value数据,而是将refcount++,变量销毁时将refcount--,等到refcount减为0时表示已经没有变量引用这个value,将它销毁即可。

      - 从上面的zend_value结构可以看出并不是所有的数据类型都会用到引用计数,long、double直接都是硬拷贝,只有value是指针的那几种类型才__可能__会用到引用计数。

    四:写时复制

      - 引用计数,多个变量可能指向同一个value,然后通过refcount统计引用数

      - 这时候如果其中一个变量试图更改value的内容则会重新拷贝一份value修改,同时断开旧的指向

      - 写时复制的机制在计算机系统中有非常广的应用,它只有在必要的时候(写)才会发生硬拷贝,可以很好的提高效率,

    五: 变量回收

      - PHP变量的回收主要有两种:主动销毁、自动销毁。

      - 主动销毁指的就是 unset ,而自动销毁就是PHP的自动管理机制,在return时减掉局部变量的refcount,即使没有显式的return,PHP也会自动给加上这个操作

      - 另外一个就是写时复制时会断开原来value的指向,这时候也会检查断开后旧value的refcount。

    六: 垃圾回收

      -  这是变量的简单gc过程,但是实际过程中出现gc无法回收导致内存泄漏的bug,先看下一个例子:

      - 

      -  可以看到,unset($a)之后由于数组中有子元素指向$a,所以refcount > 0,无法通过简单的gc机制回收

      - 这种变量就是垃圾,垃圾回收器要处理的就是这种情况。

      - 目前垃圾只会出现在array、object两种类型中。

      - 所以只会针对这两种情况作特殊处理:当销毁一个变量时,如果发现减掉refcount后仍然大于0,且类型是IS_ARRAY、IS_OBJECT则将此value放入gc可能垃圾双向链表中,等这个链表达到一定数量后启动检查程序将所有变量检查一遍,如果确定是垃圾则销毁释放。

  • 相关阅读:
    javascript基础全等号运算符
    javascript 使用ScriptX实现打印
    跨服务器与本地服务器不同数据库的SQL操作语句
    ASP.NET网络上实现单点登录
    FGMap API 帮助文档
    基于ArcEngine写的GoogleMap地图切割程序
    基于SuperMap Objects写的GoogleMap地图切割程序(三)
    使用SuperSocket开发联网斗地主(四):出牌
    JAVA创建对象方法
    Mysql 外键约束
  • 原文地址:https://www.cnblogs.com/25-lH/p/10639612.html
Copyright © 2020-2023  润新知