【问题标题】:php garbage collection while script running脚本运行时的php垃圾收集
【发布时间】:2011-03-07 19:36:46
【问题描述】:

我有一个在 cron 上运行的 PHP 脚本,可能需要 15 分钟才能执行。每隔一段时间,我就会让它吐出 memory_get_usage() ,这样我就可以看到发生了什么。它第一次告诉我我的使用量是 10 兆。当脚本完成时,我的体重是 114 兆!

PHP 是否在脚本运行时进行垃圾收集?或者所有这些记忆发生了什么?我可以做些什么来强制垃圾收集。我的脚本正在执行的任务是每晚将几千个节点导入 Drupal。所以它经常做同样的事情。

有什么建议吗?

【问题讨论】:

    标签: php performance drupal garbage-collection


    【解决方案1】:

    尽可能使用unset(),更频繁地检查已用内存。是的,php 在一些条件下在运行时进行垃圾收集。 这是 php.net 上有用的 post

    【讨论】:

      【解决方案2】:

      如果内存增加了那么多,那么你可能没有释放它。您已经创建了内存泄漏。如果您不取消设置变量、销毁对象和/或它们超出范围,垃圾收集将无济于事。

      您是否在完成加载节点后取消它们的设置?我编写的 PHP 脚本可以运行几个小时,处理数百万条数据库记录,没有任何问题,内存使用量在非常可接受的范围内上下波动。

      【讨论】:

        【解决方案3】:

        PHP garbage collection 主要是一个引用计数器(它确实有一些循环检测。)如果您保留仍然可以访问的引用,如果不释放,这些引用很容易加起来。

        使用unset() 释放您不再使用的变量。如果您只是简单地覆盖变量(例如,使用 null),这只会允许 GC 减少该变量所需的空间量,但不会像 unset 那样实际允许销毁引用的值。

        您还应该正确释放您使用的任何资源等。

        您仍然会在运行时看到内存增加,因为 GC 可以自行决定释放它,例如当有空闲 cpu 周期或内存开始不足时。

        【讨论】:

          【解决方案4】:

          关键是你unset你的全局变量,只要你不需要它们。

          您不需要为局部变量和对象属性显式调用 unset,因为当函数超出范围或对象被销毁时,它们会被销毁。

          PHP 为所有变量保留一个引用计数,并在该引用计数变为零时立即销毁它们(在大多数情况下)。对象有一个内部引用计数,而变量本身(对象引用)每个都有一个引用计数。当所有的对象引用因为它们的引用计数达到 0 而被销毁时,对象本身将被销毁。示例:

          $a = new stdclass; //$a zval refcount 1, object refcount 1
          $b = $a;           //$a/$b zval refcount 2, object refcount 1
          //this forces the zval separation because $b isn't part of the reference set:
          $c = &$a;          //$a/$c zval refcount 2 (isref), $b 1, object refcount 2
          unset($c);         //$a zval refcount 1, $b 1, object refcount 2
          unset($a);         //$b refcount 1, object refcount 1
          unset($b);         //everything is destroyed
          

          但请考虑以下情况:

          class A {
              public $b;
          }
          class B {
              public $a;
          }
          
          $a = new A;
          $b = new B;
          $a->b = $b;
          $b->a = $a;
          unset($a); //cannot destroy object $a because $b still references it
          unset($b); //cannot destroy object $b because $a still references it
          

          这些循环引用是 PHP 5.3 的垃圾收集器发挥作用的地方。您可以使用 gc_collect_cycles 显式调用垃圾收集器。

          另请参阅手册中的Reference Counting BasicsCollecting Cycles

          【讨论】:

          • 你写的不能销毁对象 $a 因为 $b 仍然引用它但是为什么当我写 destruct class A 时这个 destruct 在 unset $a 时执行
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-03-02
          • 1970-01-01
          • 1970-01-01
          • 2013-08-01
          • 2012-04-21
          • 2019-10-01
          • 2011-12-11
          相关资源
          最近更新 更多