诊断内存泄漏 - 允许的内存大小为 # 字节已耗尽

2022-08-30 07:31:37

我遇到了可怕的错误消息,可能是通过艰苦的努力,PHP已经耗尽了内存:

文件中允许的内存大小为 #### 字节已用尽(尝试分配 #### 字节).php第 123 行

提高限制

如果您知道自己在做什么,并希望提高限制,请参阅memory_limit

ini_set('memory_limit', '16M');
ini_set('memory_limit', -1); // no limit

小心!您可能只是解决了症状,而不是问题!

诊断泄漏:

错误消息指向一行,其中包含我认为正在泄漏或不必要地积累内存的循环。我已经在每次迭代结束时打印了语句,并且可以看到该数字缓慢增长,直到达到限制:memory_get_usage()

foreach ($users as $user) {
    $task = new Task;
    $task->run($user);
    unset($task); // Free the variable in an attempt to recover memory
    print memory_get_usage(true); // increases over time
}

出于这个问题的目的,让我们假设可以想象到的最糟糕的意大利面条代码隐藏在全局范围内的某个地方 或 。$userTask

哪些工具,PHP技巧或调试巫毒教可以帮助我找到并解决问题?


答案 1

PHP 没有垃圾回收器。它使用引用计数来管理内存。因此,内存泄漏的最常见来源是循环引用和全局变量。如果你使用一个框架,恐怕你会有很多代码要拖曳才能找到它。最简单的方法是有选择地将调用放置到代码泄漏的位置,并将其缩小到代码泄漏的位置。您还可以使用 xdebug 创建代码跟踪。运行带有执行跟踪和 .memory_get_usageshow_mem_delta


答案 2

以下是我们用来识别哪些脚本在服务器上使用最多内存的技巧。

将以下代码段保存在文件中,例如:/usr/local/lib/php/strangecode_log_memory_usage.inc.php

<?php
function strangecode_log_memory_usage()
{
    $site = '' == getenv('SERVER_NAME') ? getenv('SCRIPT_FILENAME') : getenv('SERVER_NAME');
    $url = $_SERVER['PHP_SELF'];
    $current = memory_get_usage();
    $peak = memory_get_peak_usage();
    error_log("$site current: $current peak: $peak $url\n", 3, '/var/log/httpd/php_memory_log');
}
register_shutdown_function('strangecode_log_memory_usage');

通过将以下内容添加到 httpd.conf 来使用它:

php_admin_value auto_prepend_file /usr/local/lib/php/strangecode_log_memory_usage.inc.php

然后在/var/log/httpd/php_memory_log

您可能需要先写入 Web 用户才能写入日志文件。touch /var/log/httpd/php_memory_log && chmod 666 /var/log/httpd/php_memory_log


推荐