目录
什么是NOP
PHP中的空操作opcode NOP: ZEND_NOP
优化
首页 php教程 php手册 PHP中的NOP及为什么有这个opcode

PHP中的NOP及为什么有这个opcode

Jun 06, 2016 pm 08:07 PM
php 为什么 什么 这个

什么是NOP NOP 是一个特殊的opcode,表示空操作,在很多地方存在,汇编中的NOP含义也一样,机器指令中的空操作通常用来将内存地址进行对齐,以提高CPU访问内存的效率,GCC等编译器也会将特定的语句进行优化而产生空操作。 PHP中的空操作opcode NOP: ZEND_NOP

什么是NOP

NOP 是一个特殊的opcode,表示空操作,在很多地方存在,汇编中的NOP含义也一样, 机器指令中的空操作通常用来将内存地址进行对齐,以提高CPU访问内存的效率, GCC等编译器也会将特定的语句进行优化而产生空操作。

PHP中的空操作opcode NOP: ZEND_NOP

PHP基于Zend虚拟机,其他基于虚拟机的语言中大都会有类似NOP的指令, PHP文档有对此的简单说明:

<?php /*
 * no operation
 * opcode number: 0
 */
function A(){};
?>
/* VLD 的输出结果 */
line  #   op  fetch   ext return  operands
6 0   NOP              
7 1   RETURN              1
Function name: A
Compiled variables: none
line  #   op  fetch   ext return  operands
6 0   RETURN              null
登录后复制

上面的VLD结果可以看出,函数A()的声明编译后变成了NOP操作。

Zend虚拟机是高级抽象,不要考虑内存对齐等的问题,为什么还需要空操作这样的opcode呢?

原因简单讲就是:编译过程优化的结果。有的内容由于可以在编译时就可确定(称为提早绑定Early Binding), 那么一部分opcode可以在编译时替换成空操作。

我们来看看这段代码的编译结果:

<?php if(true) {
  class Foo {}
}
new Bar();
class Bar {}
filename:       /Users/reeze/Opensource/php-test/php-src-5.4/test.php
function name:  (null)
number of ops:  8
compiled vars:  none
line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
   2     0  > > JMPZ                                                     true, ->3
   3     1  >   ZEND_DECLARE_CLASS                               $0      '%00foo%2FUsers%2Freeze%2FOpensource%2Fphp-test%2Fphp-src-5.4%2Ftest.php0x106cd601f', 'foo'
   4     2    > JMP                                                      ->3
   6     3  >   ZEND_FETCH_CLASS                              4  :1      'Bar'
       4      NEW                                                      :1
       5      DO_FCALL_BY_NAME                              0
   7     6      NOP
   9     7    > RETURN
登录后复制

和前面官方函数定义代码一样,上面VLD输出的第7行看到类Bar的opcode变成了NOP,不过请留意第3行, 这一行类Foo定义的opcode是ZEND_DECLARE_CLASS,也就是类的声明。

为什么同样是类的声明,第一个类声明的OPCODE和第二个的不一样呢?

上例中的代码,在Bar类声明之前是可以执行的new Bar,但是此时Bar类的声明并没有执行到, 那为什么可以访问到Bar类呢,这是因为Bar类的声明在编译时就已经完成了, 因为Bar类已经在编译时声明好了,所以在真正执行的时候就不需要再次执行声明类的操作了, 所以它所对应的opcode被替换成NOP了。

而Foo这个类由于处在条件判断块之中,编译期无法确定Foo类是否一定会被执行,所以还是需要在 执行时来声明这个类,所以opcode没有改变。

对于使用了opcode缓存的代码来说,把函数和类的声明移到了编译时,也就减少了执行时的opcode执行, 这能加快代码的执行。

优化

你可能会想,既然类及函数的声明可以优化掉,为什么不能直接丢弃这个opcode呢? 一能减少opcode占用的内容,比如很多的框架中有大量的类定义,也能减少执行时间, 因为空操作并不是0成本的,执行NOP的时候还是需要消耗CPU的。

先看看opcode编译过程的一个重要函数:

zend_op *get_next_op(zend_op_array *op_array TSRMLS_DC)
{
  zend_uint next_op_num = op_array->last++;
  zend_op *next_op;
  if (next_op_num >= CG(context).opcodes_size) {
      if (op_array->fn_flags & ZEND_ACC_INTERACTIVE) {
          /* we messed up */
          zend_printf("Ran out of opcode space!\n"
                      "You should probably consider writing this huge script into a file!\n");
          zend_bailout();
      }
      CG(context).opcodes_size *= 4;
      op_array_alloc_ops(op_array, CG(context).opcodes_size);
  }
  next_op = &(op_array->opcodes[next_op_num]);
  init_op(next_op TSRMLS_CC);
  return next_op;
}
登录后复制

这个函数每次会返回一个zend_op(也就是opcode一个最小单位),opcode的存储空间申请和哈希表类似, 通过预先申请空间的方式,如果空间不足则适当扩容。在编译时,opcode是以文件为单位的,而通常 在一个文件中函数或类声明的个数是不会太多的。而在编译时opcode数组已经是预先申请好的,所以 及时优化掉这个opcode,而实际在编译时的内存占用也不会有任何的优化。

目前只有少数几处使用了ZEND_NOP这个opcode。读者可以参考Zend/zend_compile.c: zend_do_early_binding(), 这个函数进行就是在确定在编译时能确定的函数以及类声明,在完成函数或类的声明后将当前编译的opcode设置为ZEND_NOP。 因为后续在执行是并需要再次对该函数或类进行声明了。

NOTE 当然也并不是所有的全局类或者方法都会进行提早绑定,具体可以参考前面提到的Zend_compile.c文件的实现

在这个函数中其实可以将生成的ZEND_NOP优化掉的,比如eAccelarator扩展中就对opcode进行了优化,将ZEND_NOP从 opcode_array数组中移除了,因为使用了opcode cache扩展优化只进行一次,而执行对多次执行, 这样的优化是值得的。目前Zend引擎并没有进行任何的优化,首先从代码上来看,类和函数声明的数量和其他指令的数量 之间差很多个等级,所以至少这个地方优化的收益是有限的,为了保证Zend引擎的简洁它没有进行优化。

目前APC扩展已经基本确定为将要进入PHP默认opcode缓存的官方扩展了,那么这些优化都可以在扩展中进行, 保证Zend引擎的简单易维护更为重要。

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

PHP和Python:比较两种流行的编程语言 PHP和Python:比较两种流行的编程语言 Apr 14, 2025 am 12:13 AM

PHP和Python各有优势,选择依据项目需求。1.PHP适合web开发,尤其快速开发和维护网站。2.Python适用于数据科学、机器学习和人工智能,语法简洁,适合初学者。

PHP的当前状态:查看网络开发趋势 PHP的当前状态:查看网络开发趋势 Apr 13, 2025 am 12:20 AM

PHP在现代Web开发中仍然重要,尤其在内容管理和电子商务平台。1)PHP拥有丰富的生态系统和强大框架支持,如Laravel和Symfony。2)性能优化可通过OPcache和Nginx实现。3)PHP8.0引入JIT编译器,提升性能。4)云原生应用通过Docker和Kubernetes部署,提高灵活性和可扩展性。

PHP与其他语言:比较 PHP与其他语言:比较 Apr 13, 2025 am 12:19 AM

PHP适合web开发,特别是在快速开发和处理动态内容方面表现出色,但不擅长数据科学和企业级应用。与Python相比,PHP在web开发中更具优势,但在数据科学领域不如Python;与Java相比,PHP在企业级应用中表现较差,但在web开发中更灵活;与JavaScript相比,PHP在后端开发中更简洁,但在前端开发中不如JavaScript。

PHP的持久相关性:它还活着吗? PHP的持久相关性:它还活着吗? Apr 14, 2025 am 12:12 AM

PHP仍然具有活力,其在现代编程领域中依然占据重要地位。1)PHP的简单易学和强大社区支持使其在Web开发中广泛应用;2)其灵活性和稳定性使其在处理Web表单、数据库操作和文件处理等方面表现出色;3)PHP不断进化和优化,适用于初学者和经验丰富的开发者。

PHP的目的:构建动态网站 PHP的目的:构建动态网站 Apr 15, 2025 am 12:18 AM

PHP用于构建动态网站,其核心功能包括:1.生成动态内容,通过与数据库对接实时生成网页;2.处理用户交互和表单提交,验证输入并响应操作;3.管理会话和用户认证,提供个性化体验;4.优化性能和遵循最佳实践,提升网站效率和安全性。

PHP行动:现实世界中的示例和应用程序 PHP行动:现实世界中的示例和应用程序 Apr 14, 2025 am 12:19 AM

PHP在电子商务、内容管理系统和API开发中广泛应用。1)电子商务:用于购物车功能和支付处理。2)内容管理系统:用于动态内容生成和用户管理。3)API开发:用于RESTfulAPI开发和API安全性。通过性能优化和最佳实践,PHP应用的效率和可维护性得以提升。

PHP和Python:代码示例和比较 PHP和Python:代码示例和比较 Apr 15, 2025 am 12:07 AM

PHP和Python各有优劣,选择取决于项目需求和个人偏好。1.PHP适合快速开发和维护大型Web应用。2.Python在数据科学和机器学习领域占据主导地位。

PHP:处理数据库和服务器端逻辑 PHP:处理数据库和服务器端逻辑 Apr 15, 2025 am 12:15 AM

PHP在数据库操作和服务器端逻辑处理中使用MySQLi和PDO扩展进行数据库交互,并通过会话管理等功能处理服务器端逻辑。1)使用MySQLi或PDO连接数据库,执行SQL查询。2)通过会话管理等功能处理HTTP请求和用户状态。3)使用事务确保数据库操作的原子性。4)防止SQL注入,使用异常处理和关闭连接来调试。5)通过索引和缓存优化性能,编写可读性高的代码并进行错误处理。

See all articles