Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/244.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP:循环中存在一些内存问题_Php_Memory_Garbage Collection - Fatal编程技术网

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

PHP:循环中存在一些内存问题,php,memory,garbage-collection,Php,Memory,Garbage Collection,我有一个类似以下的片段: while (true) { $myObject = new Class(); $myOtherObject = $myObject->getSomeOtherObj(); ... $myArray = [1, 2, 3]; ... sleep(1); //Sleep at the end, to save CPU. } 这段代码应该作为守护程序服务运行,但我在实现这一点上遇到了很多困难 问题:每次迭代都会增加进程

我有一个类似以下的片段:

while (true) {
    $myObject = new Class();
    $myOtherObject = $myObject->getSomeOtherObj();
    ...
    $myArray = [1, 2, 3];
    ...
    sleep(1); //Sleep at the end, to save CPU.
}
这段代码应该作为守护程序服务运行,但我在实现这一点上遇到了很多困难

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

我试过:

  • 取消设置循环末尾的所有变量(就在
    sleep()之前)
    
  • 将所有变量设置为
    null
  • 将它们封装在单独的函数中(
    while(true){doThis();}
  • 手动调用
    gc\u collect\u cycles()
这些都不能降低内存使用率

我不知道如何强制释放所有内存。

很可能(提供了给定的信息)仍然存在对已创建对象的引用,从而阻止垃圾收集器从内存中释放。由于它基本上是对引用进行计数,因此通过复制值或小心地取消设置值,可以避免存储任何引用

通常,使用while(true)构造时,由于这个原因而不创建对象,并使其尽可能自包含,以确保实际上不会发生内存泄漏,这会更容易


我知道这个答案在直接方面没有太大帮助(而且我没有足够的代表对这个问题发表评论),但它可能会让你走上正轨。

我在这里整理我以前的评论。这并不能确切地解释如何释放分配的内存,但将引导您找到一种方法,以发现应用程序中的原因。这样,您就可以优化代码了

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

如果您已经从I/O操作返回的资源中清除了内存,并且没有注意到分配内存的显著减少,那么下一步可能是使用Blackfire()之类的工具分析应用程序

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

我的最佳猜测(由于缺乏所涉及类的内部知识)是类将其他对象指定为其属性(或者它们可能具有自引用),或者使用了数组(因为代码示例类似于实际情况)有一个对自身的引用,如果数组的大小很大,这将解释内存泄漏

如果有任何帮助,请查看php.net中的参考计数基础知识:


正如上面提到的@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.
}

这段代码应该是不言自明的。

问题在于,您处于一个无限循环中,请求没有结束。PHP的垃圾收集器设计为在请求结束时处理,否则用户将无法访问。PHP设计为被调用和丢弃,而不是不确定地保持活动状态。H因此,我建议创建一个计时作业,定期重新启动php循环,从而结束请求并释放内存。有关详细信息,请参阅。

在对该主题进行了大量研究之后,我终于确信没有办法手动强制释放内存或强制销毁对象开

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

在C#或Java中,在
while(…){}
中创建的变量只能从循环中访问。这不是PHP的标准。在
while
指令中创建的
$myObject
可以在整个应用程序中访问

这意味着所提供的代码段最好呈现为:

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的函数).

你到底想做什么,这似乎是一个无限循环!无限循环是要避免的事情这是一个无限循环,因为这是一个守护进程服务。这将听到一些更改,永远不会退出。我真的需要解释守护进程服务的概念吗?@zairwolf你说的基本上是“要释放内存,请退出程序,然后重新启动”。这不是答案,这是一个非常糟糕的解决方法,在我的规范中是不可能的。你能用一个有用的
来处理循环吗?很可能[…]仍然有对c的引用