php

lobo · 2018-08-10 16:46:00 · 1780 次点击 · 预计阅读时间 1 分钟 · 大约8小时之前 开始浏览    
这是一个创建于 2018-08-10 16:46:00 的文章,其中的信息可能已经有所发展或是发生改变。

image.png

一、变量实现 (???? http://www.laruence.com/2018/04/08/3170.html)

1、PHP5与PHP7比较

在PHP5的Zend Engine的实现中,所有的值都是在堆上分配空间,并且通过引用计数和垃圾收集来管理.

PHP5的Zend Engine主要使用指向zval结构的指针来操作值,在很多地方甚至通过zval的二级指针来操作.

PHP7中的zval, 已经变成了一个值指针, 它要么保存着原始值, 要么保存着指向一个保存原始值的指针. 也就是说现在的zval相当于PHP5的时候的zval *. 只不过相比于zval *, 直接存储zval, 我们可以省掉一次指针解引用, 从而提高缓存友好性。

在PHP7移除了MAKE_STD_ZVAL/ALLOC_ZVAL宏, 不再支持存堆内存上申请zval. 函数内部使用的zval要么来自外面输入, 要么使用在栈上分配的临时zval.这样大大减少了在堆上分配和释放内存的操作,还避免了对简单值的引用计数和垃圾收集.

2、PHP变量写时分离

<?php

$a = 1;

$b = $a;

$c = &$a;

?>

变量会在改变时,判断是否复制变量。

image.png


有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1780 次点击  
加入收藏 微博
13 回复  |  直到 2019-12-30 15:01:00
lobo
lobo · #1 · 7年之前

1、

lobo
lobo · #2 · 7年之前

PHP编译、执行过程是分离的:

一、PHP的编译:

1、PHP代码 经过 词法分析、语法分析 生成抽象语法树(AST);

2、zend引擎会把AST进一步解析编译为 zend_op_array

PHP主脚本会生成一个zend_op_array,每个function也会编译为独立的zend_op_array,所以从二进制程序的角度看zend_op_array包含着当前作用域下的所有堆栈信息,函数调用实际就是不同zend_op_array间的切换。

PHP代码不会直接编译为机器码,但编译、执行的设计跟C程序是一致的,也有常量区、变量也通过偏移量访问、也有虚拟的执行栈。

lobo
lobo · #3 · 7年之前

opcode: php代码编译产生的zend虚拟机可识别的指令,php7有173个opcode,定义在 zend_vm_opcodes.hPHP中的所有语法实现都是由这些opcode组成的。

lobo
lobo · #4 · 7年之前

分享文章:http://gywbd.github.io/posts/2016/2/zend-execution-engine.html

进程虚拟机(process virtual machine)通过提供一个抽象的平台独立的程序执行环境来执行某种计算机程序。进程VM(译注:VM是virtual machine的缩写)有时候也被称为应用程序虚拟机,或者是可管理运行环境(Manged Runtime Environment,简称MRE),它会以一个普通应用的形式运行在宿主操作系统中(host OS),在运行中,他是宿主操作系统中一个单独的进程。在这个进程启动时,VM会被创建,退出时则会被销毁。它的目的是提供一种平台独立的程序执行环境,它可以对底层硬件或操作系统进行抽象处理,从而保证应用程序可以在任何平台上以一致的行为执行。

Zend虚拟机:1、编译栈(compile stack):识别PHP语言指令,把它们转换为中间形式; 2、执行栈(execution stack):获取中间形式的代码指令并在引擎上执行,引擎是用C或者汇编编写成的

Zend引擎把PHP脚本转换为一个“OP数组(OP array)”,它是一个包含多个OPCode的数组。每个OPCode的handler都会以调用ZEND_VM_NEXT_OPCODE()结束,它会告诉executor提取(fetch)紧接着的下一个OPCode,然后执行它,这个过程会不断进行。

lobo
lobo · #5 · 6年之前

php5 变量内存使用情况

1、变量结构(64位系统)

为了解决引用计数无法检查并释放循环引用(使用的内存)这问题,PHP 使用了循环回收的方法。当一个 zval 的计数减一时,就有可能属于循环的一部分,这时将 zval 写入到『根缓冲区』中。当缓冲区满时,潜在的循环会被打上标记并进行回收。

实际使用

// 32字节

typedef struct _zval_gc_info {

zval z;

union {

    gc_root_buffer       *buffered;

    struct _zval_gc_info *next;

} u;

} zval_gc_info;

// 24字节

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;

// 16字节

struct _zend_object_value {

 zend_object_handle handle;

 const zend_object_handlers *handlers;

} zend_object_value;

此外 在堆(相对于栈)分配给 zval 的内存需要额外的字节

循环引用实例:

当对象A和对象B,相互引用了对方作为自己的成员变量,只有自己销毁的时,才能将成员变量的引用计数减1

,因为对象A的销毁依赖于对象B的销毁, 对象B的销毁依赖于对象A的销毁,这样子就造成了循环引用,即使外部没有指针能够访问他们,但是他们依然不能被释放.

引用计数这种管理内存的方式虽然简单,但他不能很好的解决循环引用的问题

lobo
lobo · #6 · 6年之前

查看PHP编译opcode扩展vld

git地址: https://github.com/derickr/vld.git

php -dvld.active=1 -dvld.execute=0 test.php

lobo
lobo · #7 · 6年之前
lobolobo #2 回复

PHP编译、执行过程是分离的: 一、PHP的编译: 1、PHP代码 经过 词法分析、语法分析 生成抽象语法树(AST); 2、zend引擎会把AST进一步解析编译为 zend_op_array PHP主脚本会生成一个zend_op_array,每个function也会编译为独立的zend_op_array,所以从二进制程序的角度看zend_op_array包含着当前作用域下的所有堆栈信息,函数调用实际就是不同zend_op_array间的切换。 PHP代码不会直接编译为机器码,但编译、执行的设计跟C程序是一致的,也有常量区、变量也通过偏移量访问、也有虚拟的执行栈。

各过程的意义:

1、 词法分析的作用就是将整个源程序分解成一个一个的单词, 这样做可以在一定程度上减少后面分析工作需要处理的个体数量,为语法分析等做准备。 除了拆分工作,更多的时候它还承担着清洗源程序的过程,比如清除空格,清除注释等。

2、语法分析器(Parser)通常是作为编译器或解释器的组件出现的,它的作用是进行语法检查、并构建由输入的单词组成的数据结构(一般是语法分析树、抽象语法树等层次化的数据结构)。

lobo
lobo · #8 · 6年之前
lobo
lobo · #9 · 6年之前
lobo
lobo · #10 · 6年之前
lobo
lobo · #11 · 6年之前
lobo
lobo · #12 · 5年之前

PHP自动加载spl_autoload_register和__autoload, https://www.jb51.net/article/37906.htm

spl_autoload_register 优势: 1、 遇到不存在文件是并不抛出异常中断程序,所以对于代码管理删除老代码,而有些遗留调用,不至于使得线上程序崩溃 2、可以注册多个自动加载函数,更加精准灵活,这样我们就不用维护一个非常复杂的__autoload函数了

lobo
lobo · #13 · 5年之前
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传