PHP:循环中存在一些内存问题

2022-08-30 20:02:03

我有一个类似于以下内容的代码段:

while (true) {
    $myObject = new Class();
    $myOtherObject = $myObject->getSomeOtherObj();
    ...
    $myArray = [1, 2, 3];
    ...
    sleep(1); //Sleep at the end, to save CPU.
}

这个代码片段应该作为守护进程服务运行,但我在制作这个工作时遇到了很多麻烦。

问题:每次迭代都会增加进程内存使用量。就好像在每次新的迭代中,都会实例化一个新的迭代,但前一个迭代仍然在内存中分配,等等。$myObject

我试过:

  • 到循环末尾的所有变量(紧挨着 )。unsetsleep()
  • 将所有变量设置为 。null
  • 将它们封装在单独的函数(while (true) { doThis(); })
  • 手动呼叫gc_collect_cycles()

这些都不能减少内存使用率。

我不知道如何强制释放所有的记忆。


答案 1

经过对这个主题的大量研究,我终于确信没有办法手动强制释放内存或强制销毁对象。

但是,帮助我降低内存使用率的东西(绝对防止无限内存堆叠是不可能的)是意识到PHP中没有循环作用域,并且在切换作用域时会发生垃圾回收。

在 C# 或 Java 中,在 中创建的变量只能从循环中访问。这不是 PHP 的常态。从指令中创建的 A 可在整个应用程序中访问。while (...) {}$myObjectwhile

这意味着提供的代码段最好显示为:

while (true) {
    myFunc();
}

function myFunc()
{
    $myObject = new Class();
    $myOtherObject = $myObject->getSomeOtherObj();
    ...
    $myArray = [1, 2, 3];
    ...
    sleep(1); //Sleep at the end, to save CPU.
}

将逻辑封装在函数中会强制更改范围,这意味着每次迭代都将调用垃圾回收器。这并没有解决我的问题,但它在一定程度上降低了我的RAM使用率。

我从这次经历中学到的是,PHP可能不适合这个特定的项目要求。我需要对内存进行更多的控制,而PHP不提供对创建/销毁的对象的任何控制。某些本机函数无法正确释放内存(特别是那些执行 I/O、数据库访问和 memcached 的函数)。


答案 2

我在这里的答案中编译了我之前的评论。这并不能确切地解释如何释放分配的内存,但它将指导您通过一种方法来发现应用程序中导致这种情况的原因。这样,您就可以优化代码。

查找内存使用瓶颈通常是一项具有挑战性的任务。您可以从查看与 I/O 相关的调用开始,例如数据库查询、文件访问甚至网络。除了增加执行时间之外,有时这些操作还可以分配一定量的内存。

如果您已经从内存中删除了 I/O 操作返回的资源,并且没有注意到分配的内存大幅减少,则下一步可能是使用 Blackfire (https://blackfire.io/) 等工具分析应用程序。

Blackfire将为您提供每个函数调用的详细视图及其在内存,CPU和执行时间方面的统计信息。使用这些数据,可以检查哪些操作分配了过多的内存。当您将鼠标指针悬停在呼叫详细信息中的内存栏上时,可以找到此信息,如下所示:

Allocated memory


推荐