我有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