脚本运行时的 php 垃圾回收

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

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

有什么建议吗?


答案 1

关键是,只要不需要全局变量,就立即取消设置它们。

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

PHP 保留所有变量的引用计数,并在此引用计数变为零后立即销毁它们(在大多数情况下)。对象有一个内部引用计数,变量本身(对象引用)每个都有一个引用计数。当所有对象引用都因其引用 coutns 已达到 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显式调用垃圾回收器。

另请参阅手册中的参考计数基础知识收集周期


答案 2

PHP垃圾回收主要是一个引用计数器(它确实有一些周期检测)。如果您保留的引用仍然可以访问,那么如果不释放这些引用,这些引用将很容易加起来。

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

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

在运行时,您仍将看到内存增加,因为 GC 可以自由地以自己的分置方式释放它,例如,当有空闲 CPU 周期或内存开始不足时。


推荐