简介
在PHP的生命周期中
词法分析(zend_language_scanner),将PHP代码转换为语言片段(Tokens) 语法分析(zend_language_parser)将Tokens转换成简单而有意义的表达式 编译(compiler),将表达式编译成Opocdes,返回zend_op_array指针 Zend Engine(zend_vm_execute),顺次执行Opcodes,每次一条, 根据传入的zend_op_array指针,执行opcode并将结果返回输出
在上述执行过程中,经常被人提起的解释型语言性能问题也就是因为每次执行脚本,上述过程都会重复执行。因此,也就出现了APC, xcache, eAccelerator等缓存,不过现在官方主推的是opcache
什么是opcode缓存
当解释器完成对脚本代码的分析后,便将它们生成可以直接运行的中间代码,也称为操作码(Operate Code,opcode)。Opcode cache的目地是避免重复编译,减少CPU和内存开销。如果动态内容的性能瓶颈不在于CPU和内存,而在于I/O操作,比如数据库查询带来的磁盘I/O 开销,那么opcode cache的性能提升是非常有限的。也就是opcode cache能带来CPU和内存开销的降低
APC, xcache, eAccelerator,opcache 使用共享内存进行存储,并且可以直接从中执行文件,而不用在执行前“反序列化”代码
词法分析
Zend/zend_language_scanner.c 会根据Zend/zend_language_scanner.l(Lex文件),来对输入的 PHP代码进行词法分析,从而得到一个一个的“词”,PHP4.2+开始提供了一个函数叫token_get_all ,这个函数就可以将一段PHP代码 Scanning成Tokens
一、安装VLD扩展
1、下载
地址:http://pecl.php.net/package/vld
wget http://pecl.php.net/get/vld-0.13.0.tgz
2、编译安装
cd /usr/local/src/ wget http://pecl.php.net/get/vld-0.13.0.tgz tar -zxf vld-0.13.0.tgz cd vld-0.13.0 phpize && ./configure --with-php-config=php-config --enable-vld make && make install echo extension=vld.so >> /etc/php.d/vld.ini service php-fpm reload php-config、phpize要加入环境变量
3、opcode的结构
vim Zend/zend_compile.h
typedef struct _zend_op_array zend_op_array; typedef struct _zend_op zend_op;
struct _zend_op { opcode_handler_t handler; znode_op op1; znode_op op2; znode_op result; ulong extended_value; uint lineno; zend_uchar opcode; zend_uchar op1_type; zend_uchar op2_type; zend_uchar result_type; };
struct _zend_op_array { /* Common elements */ zend_uchar type; const char *function_name; zend_class_entry *scope; zend_uint fn_flags; union _zend_function *prototype; zend_uint num_args; zend_uint required_num_args; zend_arg_info *arg_info; /* END of common elements */ zend_uint *refcount; zend_op *opcodes; zend_uint last; zend_compiled_variable *vars; int last_var; zend_uint T; zend_brk_cont_element *brk_cont_array; int last_brk_cont; zend_try_catch_element *try_catch_array; int last_try_catch; /* static variables support */ HashTable *static_variables; zend_uint this_var; const char *filename; zend_uint line_start; zend_uint line_end; const char *doc_comment; zend_uint doc_comment_len; zend_uint early_binding; /* the linked list of delayed declarations */ zend_literal *literals; int last_literal; void **run_time_cache; int last_cache_slot; void *reserved[ZEND_MAX_RESERVED_RESOURCES]; };
4、opcode的使用
STD_PHP_INI_ENTRY("vld.active", "0", PHP_INI_SYSTEM, OnUpdateBool, active, zend_vld_globals, vld_globals) STD_PHP_INI_ENTRY("vld.skip_prepend", "0", PHP_INI_SYSTEM, OnUpdateBool, skip_prepend, zend_vld_globals, vld_globals) STD_PHP_INI_ENTRY("vld.skip_append", "0", PHP_INI_SYSTEM, OnUpdateBool, skip_append, zend_vld_globals, vld_globals) STD_PHP_INI_ENTRY("vld.execute", "1", PHP_INI_SYSTEM, OnUpdateBool, execute, zend_vld_globals, vld_globals) STD_PHP_INI_ENTRY("vld.verbosity", "1", PHP_INI_SYSTEM, OnUpdateBool, verbosity, zend_vld_globals, vld_globals) STD_PHP_INI_ENTRY("vld.format", "0", PHP_INI_SYSTEM, OnUpdateBool, format, zend_vld_globals, vld_globals) STD_PHP_INI_ENTRY("vld.col_sep", " ", PHP_INI_SYSTEM, OnUpdateString, col_sep, zend_vld_globals, vld_globals) STD_PHP_INI_ENTRY("vld.save_dir", "/tmp", PHP_INI_SYSTEM, OnUpdateString, save_dir, zend_vld_globals, vld_globals) STD_PHP_INI_ENTRY("vld.save_paths", "0", PHP_INI_SYSTEM, OnUpdateBool, save_paths, zend_vld_globals, vld_globals) STD_PHP_INI_ENTRY("vld.dump_paths", "1", PHP_INI_SYSTEM, OnUpdateBool, dump_paths, zend_vld_globals, vld_globals)
这些是vld的系统配置
默认值
static void vld_init_globals(zend_vld_globals *vld_globals) { vld_globals->active = 0; vld_globals->skip_prepend = 0; vld_globals->skip_append = 0; vld_globals->execute = 1; vld_globals->format = 0; vld_globals->col_sep = " "; vld_globals->path_dump_file = NULL; vld_globals->dump_paths = 1; vld_globals->save_paths = 0; vld_globals->verbosity = 1; }
php -dvld.active=1 -dvld.execute= -f test.php
[root@localhost code]# php -dvld.active test.php Finding entry points Branch analysis from position: 0 Jump found. Position 1 = -2 filename: /data/code/test.php function name: (null) number of ops: 5 compiled vars: none line #* E I O op fetch ext return operands ------------------------------------------------------------------------------------- 2 0 E > SEND_VAL 'dbname' 1 DO_FCALL 1 $0 'config' 2 SEND_VAR_NO_REF 6 $0 3 DO_FCALL 1 'var_dump' 3 4 > RETURN 1 branch: # 0; line: 2- 3; sop: 0; eop: 4; out1: -2 path #1: 0,
更多指令参见:http://php.net/manual/en/internals2.opcodes.list.php,同时列出了每条指令的案例