PHP垃圾收集和内存优化



我正在做一些PHP内存基准测试,我想知道是否有一种方法可以优化垃圾收集器以减少内存消耗(在其他语言中,如JAVA)。

我在php.ini中只找到了三个与GC相关的可自定义参数:session.gc_probabilitysession.gc_divisorsession.gc_maxlifetime。这只是针对会话,我并没有对此进行基准测试。

到目前为止,我所知道的可能的优化是与代码相关的,比如避免循环引用,以及通过调用gc_collect_cycles()强制执行垃圾收集循环(感谢本文http://www.alexatnet.com/comment/86)。

有人知道PHP内存管理中的配置技巧或良好实践吗?

据我所知,使用gc_collect_cycles()强制收集是最接近于在时间t最小化内存使用的方法。

GC当然是一个有时间限制的操作,应用程序很少有严格的内存限制,因此在整个程序执行过程中提供不必要地触发GC运行的选项是没有意义的。按照这种思路,PHP确实提供了按需打开和关闭循环收集器(gc_enable()gc_disable())的能力,这样您就可以根据时间优化代码(避免GC决定启动的开销)——当然,很容易看出这可能有多有用。

一般来说,PHP从哲学上避免了诸如内存管理和GC之类的主题,您的基准测试可能应该注意这一点,以获得更真实的前景。

希望这能有所帮助。

(对@GordonM引用微优化的评论表示赞同。)

通常,PHPs的内存管理对您声明和使用的所有变量都是开箱即用的。使用refcounting概念,PHP可以查看变量是否不再使用,然后自动清理它。

垃圾收集器只对对象具有循环引用的情况感兴趣,A指向B,B指向A。在这种情况下,引用计数不起作用。

如果PHP内存中正好有10.000个对象可能是循环的,可能不再使用,那么PHP垃圾收集器会在启用时触发,默认情况下是这样。您可以在运行时使用gc_enable()gc_disable()禁用或启用它。

您也可以调用gc_collect_cycles()手动清理这些对象。

但是,如果需要的话,如何优化这个过程呢?运行循环收集器并不一定要高效或有用,从10000个潜在对象来看,其中许多对象可能仍在使用中,无法清理。在这种情况下,检查所有对象并决定不清理它们是在浪费CPU周期。如果你这样做,就不会减少内存。

GC通常只在长时间运行的脚本中触发,有时只在创建过多对象的短时间web请求中触发。一般来说,你不应该想太多,因为默认情况适用于99%的用例。

使用"garbage_stats"PHP扩展,您可以访问有关GC运行效率和速度以及减少内存的度量和统计信息。它在PHP7+上工作(因为钩子从那时起才可用):https://github.com/tideways/php_garbage_stats

如果您已经安装了扩展,您可以通过调用以下命令来查看CLI脚本的垃圾收集统计信息:

$ php -dgc_stats.enable=1 -dgc_stats.show_report=1 test.php
Found 7 garbage collection runs in current script.
Collected | Efficency% | Duration | Memory Before | Memory After | Reduction% | Function
----------|------------|----------|---------------|--------------|------------|---------
        0 |     0.00 % |  0.01 ms |        365824 |       366320 |    -0.14 % | gc_collect_cycles
    10000 |   100.00 % |  2.75 ms |       4651320 |       491816 |    89.43 % | foo
    10000 |   100.00 % |  3.54 ms |       4652784 |       493280 |    89.40 % | foo
    10000 |   100.00 % |  2.11 ms |       4654248 |       494744 |    89.37 % | foo
    10000 |   100.00 % |  3.26 ms |       4656168 |       496664 |    89.33 % | Test::foo
     9000 |    90.00 % |  1.51 ms |       4694680 |       951176 |    79.74 % | Test::foo
    10000 |   100.00 % |  3.11 ms |       5112272 |       952768 |    81.36 % | Test::foo

从web(例如Apache或FPM)请求中,可以使用函数$runs = gc_stats();访问这些信息并将其写入日志文件。

基于这些信息,您可以做出唯一可能优化的决定:根据GC的运行效率在脚本中启用或禁用GC。

当我不再需要变量时,我使用unset()方法来清除它。

相关内容

  • 没有找到相关文章

最新更新