如何调试php;“内存不足”;问题?

如何调试php;“内存不足”;问题?,php,debugging,memory,methodology,Php,Debugging,Memory,Methodology,我最近在PHP内存限制方面遇到了一些问题: 内存不足(已分配22544384)(尝试分配232字节) 这些都是相当讨厌的调试,因为我没有留下很多关于是什么导致了问题的信息 添加一个关机功能有帮助 register_shutdown_function('shutdown'); 然后,使用();我可以获得关于最后一个错误的信息,在本例中是“内存不足”致命错误,例如行号和php文件名 这很好,但是我的php程序非常面向对象。堆栈深处的错误并不能告诉我关于出错时的控制结构或执行堆栈的很多信息。我已经试

我最近在PHP内存限制方面遇到了一些问题:

内存不足(已分配22544384)(尝试分配232字节)

这些都是相当讨厌的调试,因为我没有留下很多关于是什么导致了问题的信息

添加一个关机功能有帮助

register_shutdown_function('shutdown');
然后,使用();我可以获得关于最后一个错误的信息,在本例中是“内存不足”致命错误,例如行号和php文件名

这很好,但是我的php程序非常面向对象。堆栈深处的错误并不能告诉我关于出错时的控制结构或执行堆栈的很多信息。我已经试过了,但这只是显示了关机时的堆栈,而不是出错时的堆栈

我知道我可以使用ini_set或修改php.ini来提高内存限制,但这并不能让我更接近于真正了解是什么消耗了这么多内存,或者在错误期间执行流是什么样子


有没有人有一种很好的方法来调试高级面向对象PHP程序中的内存错误?

检查函数的文档以查看运行时的内存使用情况。

用于分析内存使用情况。

我想知道的是,您关于该方法的想法是否有缺陷

您的问题的基本答案-我如何找出此错误发生的位置?-已经得到答复;你知道是什么引起的

然而,在这种情况下,触发错误并不是真正的问题——当然,232字节的对象根本不是你的问题。这是之前分配的20+兆欧

有一些想法可以帮助你找到答案;您确实需要在这里查看“更高级别”,即应用程序体系结构,而不仅仅是单个功能

您的应用程序可能需要更多的内存来完成它所做的事情,而您的用户负载是有限的。或者可能有一些真正的内存消耗是不必要的,但是你必须知道什么是必要的,或者不需要回答这个问题

这基本上意味着一行一行,一个对象一个对象,根据需要分析,直到你找到你想要的;大内存用户。请注意,可能没有一个或两个大项目。。。要是这么容易就好了!一旦你找到了内存消耗,你就必须弄清楚它们是否可以被优化。如果没有,则需要更多内存。

echo';
echo '<pre>';
$vars = get_defined_vars();
foreach($vars as $name=>$var)
{
    echo '<strong>' . $name . '</strong>: ' . strlen(serialize($var)) . '<br />';
}
exit();

/* ... Code that triggers memory error ... */
$vars=get_defined_vars(); foreach($vars as$name=>$var) { 回显“”.$name.:”.strlen(序列化($var))。
; } 退出(); /* ... 触发内存错误的代码*/
我使用它在代码的问题部分之前打印出当前分配的变量列表,以及变量大小的(非常)粗略估计。我回去,在兴趣点和兴趣点之外,取消设置任何不需要的内容

当安装扩展不是一个选项时,它很有用

您可以修改上述代码以使用
memory\u get\u usage
,从而对变量中的内存进行不同的估计,而不确定它是更好还是更差

网站“IF!1 0”提供了一个简单易用的类。它对于调试内存泄漏非常有用

是一个php扩展,可以帮助查找那些内存消耗程序片段,特别是在面向对象的代码中

这很有用

注意:我试图为windows编译此扩展,但未成功。如果您尝试这样做,请确保您的php不是线程安全的。为了避免一些麻烦,我建议您在*nix环境下使用它


另一个有趣的链接是一个描述php如何处理内存的链接。它为您提供了有关脚本内存使用情况的一些线索。

232字节,您是否遇到了内存不足的问题?o、 您在对象中存储了哪些需要20多兆ram的内容?@Shaz,PHP死掉了,因为它无法在迄今为止已分配的内容(即内存限制)上再分配232字节。请看。@Marc,这就是我试图找到的:PThanks。我知道memory\u get\u usage(),但在我的代码库中随意删除它们,希望在峰值时捕获内存使用,这似乎有点草率和低效。不过,我对使用这个函数的方法感兴趣。谢谢你-当我已经获得了一些关于这个问题的线索时,xdebug似乎是一个很好的解决方案。我遇到的问题是,应用程序非常庞大,除了发生错误的行号和文件名之外,我对这些问题一无所知。当然,如果您发现您的应用程序正在使用20 MB的内存,并且您不知道为什么,那么是时候退一步,重新审视一下体系结构了。花几天的时间来检查一下,看看调用图,看看内存配置文件,不要害怕重构!这不一定是架构问题。您可以通过意外的无限递归或无休止的循环来避免内存错误,无论您分配了多少内存,这些错误都会占用所有内存。
<?php

class MemoryUsageInformation
{

    private $real_usage;
    private $statistics = array();

    // Memory Usage Information constructor
    public function __construct($real_usage = false)
    {
        $this->real_usage = $real_usage;
    }

    // Returns current memory usage with or without styling
    public function getCurrentMemoryUsage($with_style = true)
    {
        $mem = memory_get_usage($this->real_usage);
        return ($with_style) ? $this->byteFormat($mem) : $mem;
    }

    // Returns peak of memory usage
    public function getPeakMemoryUsage($with_style = true)
    {
        $mem = memory_get_peak_usage($this->real_usage);
        return ($with_style) ? $this->byteFormat($mem) : $mem;
    }

    // Set memory usage with info
    public function setMemoryUsage($info = '')
    {
        $this->statistics[] = array('time' => time(),
            'info' => $info,
            'memory_usage' => $this->getCurrentMemoryUsage());
    }

    // Print all memory usage info and memory limit and 
    public function printMemoryUsageInformation()
    {
        foreach ($this->statistics as $satistic)
        {
            echo "Time: " . $satistic['time'] .
            " | Memory Usage: " . $satistic['memory_usage'] .
            " | Info: " . $satistic['info'];
            echo "\n";
        }
        echo "\n\n";
        echo "Peak of memory usage: " . $this->getPeakMemoryUsage();
        echo "\n\n";
    }

    // Set start with default info or some custom info
    public function setStart($info = 'Initial Memory Usage')
    {
        $this->setMemoryUsage($info);
    }

    // Set end with default info or some custom info
    public function setEnd($info = 'Memory Usage at the End')
    {
        $this->setMemoryUsage($info);
    }

    // Byte formatting
    private function byteFormat($bytes, $unit = "", $decimals = 2)
    {
        $units = array('B' => 0, 'KB' => 1, 'MB' => 2, 'GB' => 3, 'TB' => 4,
            'PB' => 5, 'EB' => 6, 'ZB' => 7, 'YB' => 8);

        $value = 0;
        if ($bytes > 0)
        {
            // Generate automatic prefix by bytes 
            // If wrong prefix given
            if (!array_key_exists($unit, $units))
            {
                $pow = floor(log($bytes) / log(1024));
                $unit = array_search($pow, $units);
            }

            // Calculate byte value by prefix
            $value = ($bytes / pow(1024, floor($units[$unit])));
        }

        // If decimals is not numeric or decimals is less than 0 
        // then set default value
        if (!is_numeric($decimals) || $decimals < 0)
        {
            $decimals = 2;
        }

        // Format output
        return sprintf('%.' . $decimals . 'f ' . $unit, $value);
    }

}