我有一个类似于以下内容的代码段:
while (true) {
$myObject = new Class();
$myOtherObject = $myObject->getSomeOtherObj();
...
$myArray = [1, 2, 3];
...
sleep(1); //Sleep at the end, to save CPU.
}
此代码段应作为守护程序服务运行,但我在执行此操作时遇到了很多麻烦。
问题:每次迭代都会增加进程内存使用量。好像在每次新的迭代中都要实例化一个新的$myObject
,但前一个仍在内存中分配,等等。
我试过了:
unset
循环结束时的所有变量(就在sleep()
之前)。 null
。 while (true) { doThis(); }
)gc_collect_cycles()
这些都没有减少内存使用量。
我不知道如何强制释放所有内存。
答案 0 :(得分:6)
我在这里的答案中编写了我之前的评论。这并不能完全解释如何释放已分配的内存,但会引导您通过一种方式来发现应用程序中的内容。有了它,您可以优化代码。
查找内存使用瓶颈通常是一项具有挑战性的任务。您可以从查看与I / O相关的调用开始,例如数据库查询,文件访问甚至网络。除了增加执行时间,有时这些操作可以分配一些内存。
如果您已经从I / O操作返回的资源中清除了内存,并且没有注意到分配的内存大幅减少,则下一步可能是使用Blackfire等工具分析您的应用程序(https://blackfire.io/ )。
Blackfire将为您提供每个函数调用的详细视图及其有关内存,CPU和执行时间的统计信息。利用该数据,可以检查哪些操作正在分配过多的存储器。当您将鼠标指针放在通话详细信息中的内存条上时,可以找到此信息,如下所示:http://i.imgur.com/762mWmF.png
答案 1 :(得分:4)
经过对该主题的大量研究后,我终于确信没有办法手动强制释放内存或强制对象破坏。
但是,有些东西帮助我降低了内存使用率(绝对无法阻止无限内存堆叠)是为了意识到PHP中存在无循环范围并且切换时发生了垃圾收集范围。
在C#或Java中,只能在循环内访问在while (...) {}
内创建的变量。这不是PHP的标准。在$myObject
指令中创建的while
可在整个应用程序中访问。
这意味着所提供的代码段将更好地呈现为:
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 :(得分:2)
很可能(提供给出的信息)仍然存在对创建的对象的引用,这些引用阻止垃圾收集器从内存中removing the object。由于它基本上是在计算引用,因此确保不存储引用,通过复制值或小心地取消它们,可以避免这种情况。
通常情况下,使用while(true)构造时不会因为这个原因而精确地创建对象并使其尽可能自包含,以确保实际上不会发生内存泄漏。
我知道这个答案并没有直接帮助(我没有足够的代表对这个问题发表评论),但它可能会让你走上正轨。
答案 3 :(得分:1)
我最好的猜测(由于缺乏对所涉及类的内部的了解),要么是将其他对象分配为其属性(或者可能是自引用),要么使用数组(因为代码示例)类似于真实案例)有自己的引用,如果数组的大小很重要,它将解释内存泄漏。
如果有任何帮助,请查看php.net的参考计数基础:
答案 4 :(得分:0)
正如上面提到的@ m1lt0n和@MartPluijmaekers,这可能是与对象引用相关的问题。
我们不知道您的Class()
班级和getSomeOtherObj()
方法中有什么内容,所以我无法肯定地说出任何内容,但是下面的代码段可能会帮助您弄清楚是否是案件与否。
/* Here is your Class */
class Class {
public function __construct () {
$this->child = new AnotherClass( $this );
}
/* This is what you have to have ... */
protected function __destruct () {
unset( $this->child );
}
}
/* Here is the other class */
class AnotherClass {
public function __construct ( $parent ) {
$this->parent = $parent;
}
}
/* Infinite Loop */
while ( true ) {
$myObject = new Class();
$myOtherObject = $myObject->getSomeOtherObj();
$myArray = [1, 2, 3];
/* manually destroying the object */
$myObject->__destruct();
unset( $myObject );
/* rest of free-ing goes here ... */
sleep(1); //Sleep at the end, to save CPU.
}
该片段应该是不言自明的。
答案 5 :(得分:0)
问题是你处于一个无限循环中,在请求时没有结束。 PHP的垃圾收集器旨在在请求结束时处理,否则用户无法访问它。 PHP被设计为被调用和丢弃,而不是无限期地保持活着。因此它无法修复。所以,我建议创建一个chron作业,定期重启php循环,从而结束请求并释放内存。有关详细信息,请参阅this document。