php-php7性能提升-变量

为什么php7比php5性能提升那么多,都做了什么优化?

1.变量->zval->结构改变

(1)变小了

(2)结构体中共用内存,减少引用.内存降低,引用调用减少速度变快

2.怎么变的

(1)php5中 一共24字节(64位)

struct _zval_struct{
    union{
    }value;
    zend_uchar type;
}

用一个_zval_struct的结构体表示变量,因为是弱类型,有一个type,和具体的value(联合体) ,通过不同的函数去解析value,实现不同的效果

给变量添加新能力:垃圾回收(自动回收机制),需要引用计数refcount__gc;

struct _zval_struct{
    union{
    }value;
    zend_uchar type;
    zend_uint refcount__gc;
}

 再添加新能力:引用传递,需要标记变量是一个引用is_ref__gc;

struct _zval_struct{
    union{
    }value;
    zend_uchar type;
    zend_uint refcount__gc;
    zend_uchar is_ref__gc;
}

实际的变量zval结构体长成这样

struct _zval_struct{
    union{
        long lval;
        doublie dval;
        struct{
            char *val;
            int len;
        }str;
        HashTable *ht;
        zend_object_value obj;
        zend_ast *ast;
    }value;
    zend_uchar type;
    zend_uint refcount__gc;
    zend_uchar is_ref__gc;
}

(2)现有问题

a.没有预留新字段的位置,新添加功能要不外部链接,要不内部调用

b.因为a,浪费内存.只能定义独立的外部对象,和特殊的处理方法.只对对象,资源回收需要特殊的info结构体特殊处理.需要引用计数,原来是24k现在是32k,也就是一个进程使用32k的大小

c.对象,资源是引用传递,需要维护一个全局的引用信息

d.当别的地方要用string类型的val时只能复制

e.写时分离,一个数组取引用后自己变成引用,传给一个普通参数函数,需要复制当前这个引用对应的数据

function t($arr)
{

}
//第一种没有复制
$arr = [1,2,3];
t($arr);
//第二种复制了一个新的
$b = &$arr;
t($arr);

f.操作一个变量的过程,

(1)在堆上分配内存a,构建变量,MAKE_STD_ZVAL/ALLOC_ZVAL

(2)进行函数运算,修改变量

(3)返回变量,RETURN_ZVAL,这时会从内存中copy数据到需要的地方

(4)销毁申请的内存a

这块儿内存a起到一个临时数据的作用,是可以用栈来实现(栈快呀)

(3).php7 zval 16字节(64位)

分3块儿:value,u1,u2

value是具体值

u1类型信息

u2辅助字段

struct _zval_struct{
    union{
    }value;
    union{
    }u1;
    union{
    }u2;
}

 

value保持一个指针,一个double,或者一个long等,表示这个变量的值

 
  •      union {
  •           zend_long lval; /* long value */
  •           double dval; /* double value */
  •           zend_refcounted *counted;
  •           zend_string *str;
  •           zend_array *arr;
  •           zend_object *obj;
  •           zend_resource *res;
  •           zend_reference *ref;
  •           zend_ast_ref *ast;
  •           zval *zv;
  •           void *ptr;
  •           zend_class_entry *ce;
  •           zend_function *func;
  •           struct {
  •                uint32_t w1;
  •                uint32_t w2;
  •           } ww;
  •      } value;

u1保存了变量的类型

union{
    struct{
        ZEND_ENDIAN_LOHI_4(
            zend_uchar type,
            zend_uchar type_flags,
            zend_uchar const_flags,
            zend_uchar reserved
        )
    }v;
    uint32_t type_info;
}u1;

u2是扩充辅助字段

 
  •  union {
  •         uint32_t var_flags;
  •         uint32_t next; /* hash collision chain */
  •         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;

3.解决问题

1.引用计数

(1)明确一共有多少类型,有些是不需要引用计数的

#define IS_UNDEF 0
#define IS_NULL 1
#define IS_FALSE 2
#define IS_TRUE 3
#define IS_LONG 4
#define IS_DOUBLE 5
#define IS_STRING 6
#define IS_ARRAY 7
#define IS_OBJECT 8
#define IS_RESOURCE 9
#define IS_REFERENCE 10
/* constant expressions */
#define IS_CONSTANT 11
#define IS_CONSTANT_AST 12
/* fake types */
#define _IS_BOOL 13
#define IS_CALLABLE 14
/* internal types */
#define IS_INDIRECT 15
#define IS_PTR 17

 a.对于is_long,is_double不需要引用计数,直接copy赋值,用完销毁

b.只有类型没有值得也不需要引用计数,is_null,is_true,is_false

c.复杂类型,一个size_t保存不了,使用指针表示那个值,而引用计数维护在这个值本身上

举例数组: zval->_zend_array->zend_refcounted_h  gc->refcount

这个gc是一个维护在_zend_array上的结构体.

2.插播广告

(1)php5 -> php7 is_bool 拆分为is_true,is_false

(2)php5 -> php7 is_ref变为一个引用类型,原来是通过一个标识位标识

(3)php5-> php7 所有复杂类型引用计数refcount__gc 从一个数字变为一个类型zend_refcounted_h,统一了行为方式,同时还包含一些gc信息

struct _zend_array{
    zend_refcounted_h gc;
}

typedef struct _zend_refcounted_h{
    uint32_t refcount;
}zend_refcounted_h;

(4).ZEND_ENDIAN_LOHI_4它会保证在大端或者小端的机器上, 它定义的字段都按照一样顺序排列存储, 从而我们在赋值的时候, 不需要对它的字段分别赋值, 而是可以统一赋值

(5),type为什么不在value前面,如果在前面先获取type再获取value,快.因为jit以后value类型是通过推导得到,那么不需要获取type.

3.添加标记位type_flags

zval.u1.v.type_flags标记了type下的详细分类

4.内存分配

原来是24+gc_info8+php内存管理的一些字节=48

php的zval可能是符号表,临时变量,编译变量

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值