为什么PHP在编译为字节码文件时使用操作码缓存?

时间:2012-05-23 08:58:15

标签: php apc

从我的角度来看,PHP和Java都有类似的结构。首先,您编写一些高级代码,然后必须以更简单的代码格式进行翻译才能由VM执行。一个区别是,PHP直接从源代码文件中工作,而Java将字节码存储在.class文件中,VM可以从中加载它们。

现在,对快速PHP执行的要求越来越高,这使人们相信直接使用操作码更好,而不是每次用户点击文件时都要经过编译步骤。

解决方案似乎是a load of so called Accelerators,它基本上将编译结果存储在缓存中,然后使用缓存的操作码而不是再次编译。

另一种由Facebook完成的方法是将completely compile the PHP代码改为另一种语言。

所以我的问题是,为什么PHP世界中没有人在做Java所做的事情?是否有一些动态元素确实需要每次重新编译或类似的东西?否则,在代码投入生产时编译所有内容然后只需使用它就会更加智能。

5 个答案:

答案 0 :(得分:52)

最重要的区别是JVM具有完全覆盖字节码的显式规范。这使得字节码文件可移植,而不仅仅是由特定的JVM实现执行。

PHP甚至没有语言规范。 PHP操作码是特定PHP引擎的实现细节,因此您无法对它们做任何有趣的事情,并且使它们更加明显是没有意义的。

答案 1 :(得分:12)

PHP操作码与Java类文件不同。 Java类文件很好地指定,并且可以在机器之间移植。 PHP操作码不以任何方式移植。例如,它们有内存地址。它们严格来说是PHP解释器的实现细节,不应被视为Java字节码。

是否必须这样?不,可能不是。但是PHP源代码是混乱的,PHP内部社区既没有希望也没有政治意愿来实现这一点。我认为有人谈到将操作码缓存烘焙到PHP 6中,但PHP 6已经死了,我不知道这个想法的状态。

参考:我写了phc,所以我在PHP实现/编译方面已经很熟悉了几年。

答案 2 :(得分:4)

PHP世界中的 nobody 正在做java所做的事情并不完全正确。诸如Alexey Zakhlestin's appserver之类的项目提供了一定程度的持久性,更类似于java servlet容器(尽管他的灵感来自Ruby的Rack和Python的WSGI而不是Java)

答案 3 :(得分:3)

PHP不使用操作码的标准机制。我希望它坚持堆栈VM(python,java)或寄存器VM(x86,perl6等)。但是它使用的东西绝对是本土的,并且存在着瑕疵。

它使用内存中的连接列表,这导致每个操作码具有 - > op1 - > op2和 - >结果。现在每个都是临时表中的常量或条目等。这些指针不能以任何合理的方式序列化。

现在,人们已经使用像pecl / bcompiler这样的项目完成了这项工作,它会将流转储到磁盘中。

但是这些类使这更复杂,这意味着有潜在的代码片段,如

if(<conditon>)
{
   class XYZ() { }
}
else 
{
   class XYZ() { }
}

class ABC extends XYZ {}

这意味着关于课程的大量决定&amp;函数只能在运行时完成 - 像Java这样的东西会阻塞两个具有相同名称的类,这些类在运行时有条件地定义。基本上,APC的继承和类缓存代码可能是最复杂的&amp;容易出错的部分代码库。每当缓存一个类时,必须先擦除所有父继承的成员,然后才能将其保存到操作码缓存中。

指针问题并非不可克服。有一个apc_bindump,我从来没有费心去修复在重启完成后直接从磁盘加载整个缓存条目。但是调试所有这些仍然需要找到所有系统指针的东西是痛苦的 - apache的情况太容易了,因为所有的php进程都因为fork行为而具有相同的系统指针。旧的fastcgi版本速度较慢,因为他们过去常常使用init php以后 - php-fpm通过相反的方式修复了它。

但最终,PHP中真正缺少的是发明字节码格式的意愿,抛弃当前的引擎和放大器。所有模块 - 使用堆栈VM&amp;重写它建立一个JIT。我希望我有时间 - 这些家伙几乎和他们的嘻哈HHVM在一起。为了更快的性能而牺牲了eval() - 这是一个公平的牺牲:)

PS:我是那个无法及时更新APC for 5.4的人

答案 4 :(得分:3)

我想你们所有人都被误导了。 HHVM不是另一种语言编译器本身就是虚拟机。混淆是因为facebook使用编译为c ++,但这种方法是慢慢满足开发人员的要求(十分钟编译仅用于测试一些小东西)。