IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> PHP变量类型底层设计实现 -> 正文阅读

[PHP知识库]PHP变量类型底层设计实现

基础知识

每个类型的字节长度(x86-64体系)

int 4字节
char 1字节
long 8字节
pointer 8字节

字节对齐

struct test{
	char a;
	int b;
	long c;
	void *d;
	int e;
	char *f;
};

如果单独把每个类型的字节数相加是33字节,但是实际上要使用40字节
在这里插入图片描述
内存对齐的本质是cpu对程序内存数据获取的要求,这样可以加快数据IO的过程,避免不必要的计算工作。

联合

uniontest{
	char a;
	int b;
	long c;
};

联合体只共享内存,只使用最大的成员的内存大小
例如:定义一个如下c文件

union data {
    u_int32_t a;
    u_int32_t b;
    u_int32_t c;
} d;

int main() {
    d.a = 30;
    printf("a %d b %d c %d\n", d.a, d.b, d.c);

    d.b = 10;
    printf("a %d b %d c %d\n", d.a, d.b, d.c);
}

编译执行后得到的结果是,

$ gcc union.c
$ ./a.out 
a 30 b 30 c 30
a 10 b 10 c 10

有了基本认知我们再来看看zval的设计

PHP5的zval设计

PHP5中_zval_struct(zval)结构

struct _zval_struct{
	zvalue_value value; /*value值*/
	zend_uint refcount__gc; /*类型*/
	zend_uchar type; 
	zend_uchar is_ref__gc;
};
typedef union_zvalue _value {
	long lval; /*长整型*/
	double dval; /*浮点型*/
	struct{
	char *val;
	int len;
	} str;
	HashTable *ht;/*HashTable数*/
	zend_object_value obj;
	zend_ast *ast;
} zvalue_value;

通过联合结构很容易看出来,php的整形值实际上是长整型,浮点数是double,字符串是一个结构体,表示byte数组和长度;剩下部分就是数组和对象;
zval结构所表示的是一个zvalue_value和引用计数,以及变量类型和是否引用类型等。

使用zend内存池后zval结构的变化

typedef struct _zend_mm_block_info {
	size_t _size;
	size_t _prev;
} zend_mm_block_info;
typedef struct _zend_mm_block {
	zend_mm_block_infoinfo;
} zend_mm_block;

最终一个变量在PHP5中实际占用的内存大小为48字节
在这里插入图片描述
这48字节的大小其实有很多的浪费,而这点PHP开发者在PHP7中做了重点优化。

  • 题外话:PHP5.3解决循环引用
    通过重写分配zval的宏,对zval进行扩充
#undef ALLOC_ZVAL
#define ALLOC_ZVAL(z)\
	do{ \
	(z)=(zval*)emalloc(sizeof(zval_gc_info));\
	 GC_ZVAL_INIT(z);
	} while0typedef struct _zval_gc_info{
	zval z;
	union {
		gc_root_buffer* buffered;
		struct _zval_gc_info *next;
	} u;
} zval_gc_info;

从结构体看,猜测的使用的方法是通过对zval结构循环记录来判断是否变量存在循环引用,相当于对有环链表的循环查找。

PHP7的Zval设计

struct _zval_struct {
zend_value value;
union {
	struct {
		ZEND_ENDIAN_LOHI_4(
			zend_uchar type,/*标明zval类型*/
			zend_uchar type_flags,
			zend_uchar const_flags,
			zend_uchar reserved)
		} v;
	uint32_t type_info;
	} u1;
	union {
		uint32_t next; /*用来解决哈希冲突,详见第5章*/
		uint32_t cache_slot; /*运行时缓存*/
		uint32_t lineno;  /*对于zend_ast_zval存行号*/
		uint32_t num_args;/*EX(This)参数个数*/
		uint32_t fe_pos; /*foreach的位置*/
		uint32_t fe_iter_idx; /*foreach游标的标记*/
		uint32_t access_flags; /*类的常量访问标识*/
		uint32_t property_guard; /*单一属性保护*/
	} u2;
};


typedef union _zend_value {
	zend_long lval;/*整型*/
	double dval;/*浮点型*/
	zend_refcounted *counted;/*引用计数*/
	zend_string *str;/*字符串类型*/
	zend_array *arr;/*数组类型*/
	zend_object *obj;/*对象类型*/
	zend_resource *res;/*资源类型*/
	zend_reference *ref;/*引用类型*/
	zend_ast_ref *ast;/*抽象语法树*/
	zval *zv;/*zval类型*/
	void *ptr;/*指针类型*/
	zend_class_entry *ce;/*class类型*/
	zend_function *func;/*function类型*/
	struct{
		uint32_t w1;
		uint32_t w2;
	} ww;
} zend_value;
 

zval结构的主要变化时多了两个union结构,我们主要看下这个变化。

u1字段的含义

  • type:记录变量类型。
  • type_flag: 对应变量类型特有的标记,不同类型的变量对应的flag也不同
/*zval.u1.v.type_flags*/
IS_TYPE_CONSTANT//是常量类型
IS_TYPE_IMMUTABLE//不可变的类型,比如存在共享内存中的数组
IS_TYPE_REFCOUNTED//需要引用计数的类型
IS_TYPE_COLLECTABLE//可能包含循环引用的类型(IS_ARRAY,IS_OBJECT)
IS_TYPE_COPYABLE//可被复制的类型

  • const_flag:常量类型的标记,对应的属性有:
/*zval.u1.v.const_flags*/
#define IS_CONSTANT_UNQUALIFIED 0x010
#define IS_CONSTANT_VISITED_MARK 0x020
#define IS_CONSTANT_CLASS0 x080 /*__CLASS__trail类*/
#define IS_CONSTANT_IN_NAMESPACE 0x100/*只用在opline>extended_value*/
  • reserved:保留字段。

u2中的字段信息

  • next:用来解决哈希冲突问题,记录冲突的下一个元素位置
  • cache_slot:运行时缓存。在执行函数时会优先去缓存中查找,若缓存中没有,会在全局的function表中查找。
  • lineno:文件执行的行号,应用在AST节点上
  • num_args:函数调用时传入参数的个数
  • fe_pos:遍历数组时的当前位置
  • fe_iter_idx:跟fe_pos用途类似,只是这个字段是针对对象的。
  • access_flags:对象类的访问标志,常用的标识有public、protected、private。
  • property_guard:防止类中魔术方法的循环调用,

PHP7的zval的内存占用情况

在这里插入图片描述
对比PHP5的内存占用48个字节,PHP7的zval内存占用要小很多。

参考:
https://book.douban.com/subject/30455287/

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-08-23 16:25:23  更:2021-08-23 16:25:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/13 19:34:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码