php 内存计数,PHP5 内存引用计数与写时复制

内核中变量的存储方式

首先看两个C的结构:

typedef struct _zval_struct {

zvalue_value value;

zend_uint refcount__gc;

zend_uchar type;

zend_uchar is_ref__gc;

} zval;

typedef union _zvalue_value {

long lval; // 用于 bool 类型、整型和资源类型

double dval; // 用于浮点类型

struct { // 用于字符串

char *val;

int len;

} str;

HashTable *ht; // 用于数组

zend_object_value obj; // 用于对象

zend_ast *ast; // 用于常量表达式(PHP5.6 才有)

} zvalue_value;

php弱类型的实现在于以上的C片段。简单解释一下原理:

php每申明一个变量,zval会给变量一个容器,例如 $a=1; 那么系统会给int类型的a 一个容器。容器内部包含以下内容:

a的值--对应的结构体中的zvalue_value value

a的类型--对应结构体的 zend_uchar type

zend 引擎定义如下几种类型

常量定义

标识类型

#define IS_NULL

是否为空(null)

#define IS_LONG

是否为整型(int)

#define IS_DOUBLE

是否为浮点数(float)

#define IS_STRING

是否为字符串(string)

#define IS_ARRAY

是否为数组(array)

#define IS_OBJECT

是否为对象(object)

#define IS_BOOL

是否为布尔类型(bool)

#define IS_RESOURCE

是否为资源类型(resource)

不同类型对应结构体的存储:

php语言层类型

保存在zvalue_value中的成员变量

long、bool、resource

lval

double

dval

string

str(len保存长度、val保存值)

array

ht

object

obj

a这个容器是否为引用地址 --对应的是zend_uchar is_ref__gc

a被指向的集合数 --对应的是 zend_uint refcount__gc

当你申明一个变量 $a=1  系统做了如下的事情

创建结构体  ->  设置类型type 为 int   ->  设置值为zvalue_value里的long lval(string类型等其他类型依次类推)  ->  设置是否引用地址为 0 ,即不引用内存地址  ->  a的指向集合数设置为1  -> 将zval容器指向 $a

如果此时,我们将 $b=$a  那么 系统会作如下处理

根据$a 找到对应结构体 ->  设置指向集合数自增 1 ->  将zval 容器 指向 $b

如果 我们在上述基础上使用 $c=& $a 设置c的值捆绑a的地址,系统会做如下处理

根据$a 找到对应结构体  ->  设置指向集合数再次自增 1 -> 设置是否引用地址 为 1  -> 将该zval 容器 指向 $c

此时如果我们 跟新 $c的值为 2 试着sh使用 xdebug_debug_zval打印 a的值会出现如下内容

a: (refcount=2, is_ref=1)=2

原因:

因为三个变量都指向zval 的容器。并且 $c=& $a 会更改 zval 模式为引用模式。当其中一个变量值修改时 其他值由于指向同一个zval容器。所以都会改变。

引用计数与写时复制

如果执行以下代码:

$a=1;

xdebug_debug_zval('a');

$b=$a;

xdebug_debug_zval('a');

$a=2;

xdebug_debug_zval('b');

xdebug_debug_zval('a');

那么结果如下 :

a: (refcount=1, is_ref=0)=1

a: (refcount=2, is_ref=0)=1

b: (refcount=1, is_ref=0)=1

a: (refcount=1, is_ref=0)=2

过程分析:

$a 创建了 指向数为1  非地址引用并且值为int类型 1 的zval 容器;新建一个$b  也指向 $a的zval 容器。现在我们将$a的值赋值为 2 ,由于该zval 容器非地址引用,所以系统会重新创建一个指向数为1  非地址引用并且值为int类型 2的zval 容器 指向$a ,由于 $a 不再指向原zval容器 ,所以原容器的 指向数 减 1。

以上内容 就是php内核的另一个重要的特性。引用计数 与 写时复制 原理。这个原理很好的解决了 内存的复用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值