4

我有 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);
}

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

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

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

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 的工具可以提供帮助,去试试吧:)

4

6 回答 6

3

尽管 unset() 不会释放 PHP 进程消耗的内存,但它会释放它以供 PHP 脚本本身使用。

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

如果它增长 - 那么,在您不想显示的完整逻辑中的某个地方存在泄漏。

于 2013-01-15T11:13:03.980 回答
0

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

于 2013-01-15T11:09:53.010 回答
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 循环中的副本副本。

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

于 2013-01-15T11:35:42.397 回答
0

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

于 2013-01-15T11:13:59.427 回答
0

变量上的 unset() 将其标记为“垃圾收集”

你试过 __destruct() 吗?

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

于 2014-04-02T16:01:36.803 回答
0

顺便说一句,你的 foreach ... unset 循环什么也不做。PHP 使用基于引用的延迟复制写入系统来优化内存使用。这个 foreach 循环这实际上是一个无操作。存储被释放——即返回给 Zend Engines 内部的 emalloc 分配器(而不是操作系统)——或者一旦任何元素的引用计数为零,就可以重用。当你离开一个函数的作用域时,对于局部变量,当你销毁一个类对象时,对于类属性,无论如何都会发生这种情况。克隆变量的浅表副本然后取消设置是没有意义的,因为这只会对引用计数产生 +1 -1 的影响。

如果您挖掘循环中使用的主要变量的代码并取消设置它们,那么您将真正减少引用计数并降至 0,然后您将释放存储空间以供重用。然而,正如 troelskyn 所暗示的,现有代码可以通过多种方式为数据元素留下非零引用。经典的方法是,如果您的代码使用引用,那么您可以创建循环引用链,除非循环被显式破坏,否则这些引用链永远不会被回收。即使有一个用于保存结果的全局数组也会占用内存。

抱歉,您的声明:

我不想在这里展示完整的逻辑,因为对其他人来说可能需要很多时间,这不是这里的重点。

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

于 2013-01-15T16:10:47.003 回答