如何找到哪个PHP脚本泄漏内存?

2022-08-30 13:25:52

我的专用服务器有32GB RAM,内存不断上升,我现在必须每天重新启动它。这让我失去了客户和金钱。

我很难找到内存泄漏的位置。我在网上能找到的只是人们说“使用xdebug”,但我无法找到任何关于查找内存泄漏的xdebug教程。我尝试过在函数调用之前和之后打印memory_get_usage,但这是正确的方法吗?

我运行了许多php脚本 - 一些来自访问者,另一些来自cron作业 - 我需要找到其中哪些(些)正在泄漏内存并尽快修复它,但我甚至不知道如何确定给定的函数是否泄漏内存。

我尝试过在函数调用之前和之后打印memory_get_usage,并且它上升了,但是如果我多次调用该函数,它就不会再上升了。有人可以解释一下这一点,并告诉我如何简单易举地判断PHP函数是否有内存泄漏吗?


答案 1

您可以执行各种操作,但首先应首先尝试避免创建内存泄漏。

让我澄清一下:PHP是一种脚本语言,它不是为长时间运行的脚本而设计的,所以它的内存管理不是市场上最好的。但为什么会这样呢?其目的是在请求级别上调用,因此其运行范围非常小(不超过2-3秒)。其他一切都应该放在后台。

如何防止内存泄漏?

  1. 如果您使用的是低于5.4的版本,则需要注意圆圈引用,因为这些引用不是垃圾回收的。

  2. 如果需要连续运行脚本,可以考虑使用其他方法。请尝试一个实现,但要围绕脚本(http://supervisord.org)进行包装,并在脚本结束后调用它。这样,您就可以100%确保永远不会出现内存泄漏。while(true)supervisor

  3. 您可以使用逐个分析脚本并找出消耗大量内存的位置。xdebug

  4. 您可以实现一个析构函数来取消设置所有引用,如果该类不再需要。

    public function __destruct(){
        $this->cleanup();
    }
    
    public function cleanup() {
        //cleanup everything from attributes
        foreach (get_class_vars(__CLASS__) as $clsVar => $_) {
            unset($this->$clsVar);
        }
    
        //cleanup all objects inside data array
        if (is_array($this->_data)) {
            foreach ($this->_data as $value) {
                if (is_object($value) && method_exists($value, 'cleanUp')) {
                    $value->cleanUp();
                }
            }
        }
    }
    
  5. 通读有关垃圾回收 http://us3.php.net/manual/en/features.gc.php PHP 文档

  6. 避免全局变量,因为这些变量永远不会被垃圾回收,需要显式收集。如果您使用的是像ZF或Symfony这样的框架,那可能是不可能的,因为如果您这样做,您将破坏功能。unset

最后但并非最不重要的一点是,我想再次强调,PHP不适合长时间运行的脚本!如果你有事情要做,需要连续运行,你不应该在PHP中因内存泄漏而崩溃,而是花时间学习更复杂的语言,如JAVA或C#。


答案 2

看看这个php扩展:https://github.com/arnaud-lb/php-memory-profiler。您可以转储不同格式的信息,并通过一些工具对其进行简单分析,例如:Google Performance ToolsKCacheGrindQCacheGrind


推荐