PHP为什么不设置不释放内存


PHP why unset do not makes memory free?

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

很快说应用程序在周期中导出数据,如

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

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

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

如果它增长了——那么,在你不想显示的完整逻辑中的某个地方就有漏洞。

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

因为unset不会释放内存。它只是释放变量。但是,如果这个变量指向某种复杂的结构,PHP的内存管理无法找出如何释放,它就不会。

$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循环中副本的副本。

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

BTW,你的前臂。。。unset循环无论如何都不起任何作用。PHP使用基于引用的延迟写时复制系统来优化内存使用。这个foreach循环实际上是一个no-op。一旦任何元素的引用计数为零,存储空间就会被释放——返回到内部Zend Engines emalloc分配器(而不是到操作系统(——或者被重用。不管怎样,当您离开函数的作用域时,局部变量和当您销毁类对象时,类属性都会发生这种情况。克隆一个变量的浅拷贝然后取消设置是没有意义的,因为这只会对引用计数产生+1-1。

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

对不起,但您的声明:

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

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

变量上的

unset((将其标记为"垃圾收集">

你试过__destruct((吗?

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