我有一个在cron上运行的PHP脚本,最多可能需要15分钟才能执行。我定期吐出memory_get_usage()所以我可以看到发生了什么。它第一次告诉我我的用法我是10兆。当脚本完成时,我的速度为114兆!
PHP在脚本运行时是否进行了垃圾回收?或者那些记忆发生了什么?有什么我可以做的强制垃圾收集。我的脚本正在执行的任务是每晚将几千个节点导入Drupal。所以很多时候它都在做同样的事情。
有什么建议吗?
答案 0 :(得分:16)
关键是,只要您不需要它们,就unset全局变量。
您不需要为局部变量和对象属性显式调用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
显式调用垃圾收集器。
答案 1 :(得分:3)
PHP garbage collection主要是一个引用计数器(它确实有一些循环检测。)如果你保持那些仍然可以访问它们的引用,如果没有被释放就很容易加起来。
使用unset()释放您不再使用的变量。如果你只是简单地覆盖变量(例如,使用null),这将只允许GC减少到该变量所需的空间量,但不会像实际允许销毁参考值的未设置那样多。
您还应该正确释放您使用的任何资源等。
在运行期间您仍会看到内存增加,因为GC可以自行释放它,例如当有空闲的cpu周期或内存开始不足时。
答案 2 :(得分:2)
尽可能使用unset()
,更频繁地检查已用内存。是的,php在运行时在几个条件下进行垃圾收集。
这是php.net上的一个有用的post。
答案 3 :(得分:1)
如果内存增加那么多,那么你可能不会释放它。您已经创建了内存泄漏。如果您不取消设置变量,销毁对象和/或它们超出范围,垃圾收集将无法帮助您。
完成后,您是否取消了加载的节点?我编写的PHP脚本运行了几个小时,处理了数百万条数据库记录,没有任何问题和内存使用情况在可接受的范围内上下变化。