Laravel项目每20分钟触发内存耗尽错误排查求助
Laravel 5.8 内存耗尽问题排查方案
是否与Laravel相关?
报错位置在Doctrine DBAL(Laravel默认依赖的数据库操作组件),但仅有的#0 {main}栈追踪无法直接确认是Laravel核心问题。大概率是某类请求/后台操作触发的数据库逻辑导致内存泄漏,比如:
- 未正确处理的大结果集查询(未分页、未使用
chunk) - 循环内重复执行查询且未释放资源
- 自定义代码/第三方扩展中的内存泄漏,通过数据库组件触发
日志优化代码方案
以下代码可帮你捕获更多错误上下文,无需修改php.ini:
1. 监控PDO语句执行细节
在AppServiceProvider的boot方法中添加代码,拦截PDO执行过程并记录关键信息:
use Doctrine\DBAL\Driver\PDOStatement; use Illuminate\Support\Facades\Log; public function boot() { \Closure::bind(function() { $originalExecute = $this->execute; $this->execute = function($params = null) use ($originalExecute) { // 记录调用栈、SQL、当前内存 $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10); Log::warning('PDO Statement Executed', [ 'sql' => $this->queryString, 'params' => $params, 'call_stack' => $backtrace, 'current_memory' => round(memory_get_usage(true)/1024/1024, 2) . 'MB' ]); try { return $originalExecute->call($this, $params); } catch (\Throwable $e) { // 出错时记录峰值内存 Log::error('PDO Statement Failed', [ 'sql' => $this->queryString, 'params' => $params, 'call_stack' => $backtrace, 'peak_memory' => round(memory_get_peak_usage(true)/1024/1024, 2) . 'MB', 'error' => $e->getMessage() ]); throw $e; } }; }, null, PDOStatement::class)->__invoke(); }
2. 全局请求内存监控
创建app/Http/Middleware/MemoryMonitorMiddleware.php:
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Support\Facades\Log; class MemoryMonitorMiddleware { public function handle($request, Closure $next) { $startMem = memory_get_usage(true); $response = $next($request); $usedMem = round((memory_get_usage(true) - $startMem)/1024/1024, 2); // 内存占用超过50MB时记录详情 if ($usedMem > 50) { Log::warning('High Memory Request', [ 'method' => $request->method(), 'uri' => $request->fullUrl(), 'used_memory' => $usedMem . 'MB', 'peak_memory' => round(memory_get_peak_usage(true)/1024/1024, 2) . 'MB', 'client_ip' => $request->ip(), 'user_agent' => $request->userAgent() ]); } return $response; } }
然后在app/Http/Kernel.php的$middleware数组中注册该中间件,监控所有HTTP请求的内存消耗。
3. 增强致命错误日志
修改app/Exceptions/Handler.php的report方法:
public function report(Exception $exception) { if ($this->shouldReport($exception)) { // 针对内存耗尽错误补充上下文 if ($exception instanceof \ErrorException && str_contains($exception->getMessage(), 'Allowed memory size')) { Log::critical('Memory Exhausted', [ 'message' => $exception->getMessage(), 'file' => $exception->getFile(), 'line' => $exception->getLine(), 'peak_memory' => round(memory_get_peak_usage(true)/1024/1024, 2) . 'MB', 'request_uri' => request()->fullUrl() ?? 'CLI/Unknown', 'request_method' => request()->method() ?? 'CLI', 'trace' => $exception->getTraceAsString() ]); } } parent::report($exception); }
额外排查方向
- 检查服务器cron任务,确认是否有未配置的定时进程触发请求
- 查看服务器进程列表,排查是否有持续运行的PHP进程占用内存
- 核实近期用户行为,是否存在批量数据操作(导入/导出)触发高内存逻辑
内容的提问来源于stack exchange,提问作者Roman
相关产品推荐
相关产品推荐

