PHP为什么不设置不使内存空闲?

时间:2013-01-15 11:08:24

标签: php optimization

我有php应用程序应该管理(导出)大量(大量)数据,并且必须在生产中完成...所以我需要尽可能降低内存使用率(主要标准)。

简单地说App在周期中导出数据,比如

for($fileCounter=0;$fileCounter<=70;$fileCounter++) {
... HERE a lot of (more than 1K lines) huge work, many variables a lot of DB queries from another databases etc ...
}

我不想在这里展示完整的逻辑,因为它可能需要花费很多时间给其他人,这不是主要观点。

重点是,为什么如果我在每次迭代期间unset()所有新创建的变量,它不会减少内存使用量?像这样

for($fileCounter=0;$fileCounter<=70;$fileCounter++) {
    // optimization purpose
    $vars_at_start = array_keys(get_defined_vars());
    echo memory_get_peak_usage(true) . PHP_EOL;

... huge logic ...

    $vars_at_end = array_diff($vars_at_start, array_keys(get_defined_vars()));
    foreach($vars_at_end as $v) unset($v);
    unset($vars_at_end);
}

以及如何减少内存使用量?如果我需要使用这么多查询,变量等等。

P.S。代码不是我的:)我不想从头开始重写它,我只是在寻找优化方向。

没有变量清理内存使用是下一个(它是在每次迭代开始时测量)

23592960

Started: 0 - 12:58:26
Ended: 13:00:51
877920256 (difference 854'327'296)

Started: 1 - 13:00:51
Ended: 13:03:39
1559494656 (difference 681'574'400)

并使用变量清理

23592960

Started: 0 - 12:47:57
Ended: 12:50:20
877920256 (difference 854'327'296)

Started: 1 - 12:50:20
Ended: 12:53:16
1559756800 (difference 681'836'544)

根据我的阅读,PHP有很多理由泄漏内存......就像这个https://bugs.php.net/bug.php?id=48781

有一个名为valgrind的工具可以提供帮助,去尝试一下:)

6 个答案:

答案 0 :(得分:2)

尽管unset()没有释放PHP进程占用的内存,但它确实释放它以供PHP脚本本身使用。

因此,如果你在一个循环中创建一个10M大小的变量10次并在循环结束时取消设置(或重写)它,那么内存消耗应该低至10M +所有其他变量到底循环。

如果它增长 - 那么,在你不想表现的完整逻辑中的某个地方就会出现泄漏。

答案 1 :(得分:0)

因为PHP会自动完成 当不再使用变量时,PHP会自行取消它。

答案 2 :(得分:0)

因为unset没有释放内存。它只是释放变量。但是,如果该变量指向某种复杂的结构,那么PHP的内存管理无法弄清楚如何释放,它就不会。

答案 3 :(得分:0)

$vars_at_end = array_diff($vars_at_start, array_keys(get_defined_vars()));
foreach($vars_at_end as $v) unset($v);
unset($vars_at_end);

整个代码块正在处理变量的副本(甚至副本),因此它会增加大量内存。 您未设置的所有内容都是foreach循环中的副本副本。

您需要取消设置您使用的实际变量

答案 4 :(得分:0)

顺便说一句,你的foreach ...未设置的循环无论如何都没有。 PHP使用基于引用的延迟拷贝写入系统来优化内存使用。这个foreach循环实际上是一个无操作。存储被释放 - 返回到内部Zend Engines emalloc分配器(到OS) - 或者在任何元素的引用计数为零时重用。当您离开函数的范围时,无论如何都会发生这种情况,而当您销毁类对象时,这将发生在类属性中。克隆变量的浅拷贝然后取消设置是没有意义的,因为这只是引用计数的+1 -1。

如果您挖掘循环中使用的主变量的代码并取消设置它们,那么您将真正减少引用计数并减少到0,然后您将释放存储以供重用。然而,正如troelskyn所暗示的那样,现有代码可以通过许多方式使数据元素具有非零引用。经典的方法是,如果您的代码使用引用,那么您可以创建循环引用链,除非明确地断开循环,否则永远不会回收它们。即使有一个用于保存结果的全局数组也会占用内存。

很抱歉,但是你的陈述:

  

我不想在这里展示完整的逻辑,因为它可能需要花费很多时间给其他人,这不是主要观点。

错了。在PHP中,如果您想了解为什么不将存储返回到内存池,那么必须查看代码。

答案 5 :(得分:0)

变量上的

unset()标记为垃圾收集&#39;

你试过__destruct()吗?

http://www.php.net/manual/en/language.oop5.decon.php