【问题标题】:PHP Garbage collection and memory optimizationsPHP 垃圾收集和内存优化
【发布时间】:2012-02-25 11:33:14
【问题描述】:

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

我在 php.ini 中只发现了三个与 GC 相关的可自定义参数:session.gc_probabilitysession.gc_divisorsession.gc_maxlifetime。这仅适用于会话,我没有对其进行基准测试。

目前我知道的可能优化与代码相关,例如避免循环引用和通过调用 gc_collect_cycles() 强制垃圾收集周期(感谢这篇文章 http://www.alexatnet.com/comment/86)。

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

【问题讨论】:

  • 通过配置指令没有什么可以做的,只能通过以减少内存使用的方式编写代码 - 这对大多数“程序员”来说本身就是一个谜 :)跨度>
  • 除非你真的因为 GC 问题而遇到内存消耗和/或性能问题,否则我真的不会担心它,因为它大部分是micro-optimization

标签: php memory memory-management benchmarking


【解决方案1】:

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

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

一般来说,PHP 在哲学上会避免诸如内存管理和 GC 之类的主题,您的基准测试也许应该尊重这一点,以便更真实地展望。

希望这会有所帮助。

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

【讨论】:

  • 事实上,我正在搜索那种 gc 微优化。但是,显然无法调整 PHP 垃圾收集器。我想确定一下。谢谢。
【解决方案2】:

一般来说,PHP 的内存管理对您声明和使用的所有变量都是开箱即用的。使用 refcounting 的概念,PHP 会查看一个变量是否不再使用,然后自动清理它。

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

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

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

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

通常 GC 只在长时间运行的脚本中触发,有时只有在创建太多对象时才在短的网络请求中触发。一般来说,您不应该考虑太多,因为默认值适用于 99% 的用例。

通过“garbage_stats”PHP 扩展,您可以访问有关 GC 运行的效率和速度以及减少了多少内存的指标和统计信息。它适用于 PHP 7+(因为从那时起钩子才可用):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

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

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-25
      • 2017-03-15
      • 2012-11-30
      • 2012-06-28
      • 1970-01-01
      • 1970-01-01
      • 2021-11-15
      相关资源
      最近更新 更多