You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 9中如何在Dispatchable对象序列化入库后释放内存?

问题解决:Laravel批量发送大体积邮件内存耗尽问题

问题背景

在Laravel 9环境下批量给大量用户发送大体积邮件时,遭遇服务器内存耗尽的问题:

  • 自定义ProcessEmail类实现了ShouldQueue和Dispatchable接口,类内私有字段存储大体积邮件正文
  • 对象序列化后存入jobs表的存储开销可接受,但循环遍历用户时,相关对象持续滞留在内存中,导致内存占用飙升
  • 最初尝试在对象写入数据库后用unset()释放内存,但未解决问题

排查过程

深入排查后确认,内存占用过高并非ProcessEmail对象本身导致,而是项目中监听数据变更并记录日志的代码引发的额外内存开销——这类代码会在Eloquent操作过程中留存大量上下文数据,无法被及时回收。

最终解决方案

放弃使用Eloquent,直接通过PDO原生操作将邮件任务数据写入jobs表,彻底规避Eloquent带来的额外内存消耗:

// 替代Eloquent的PDO写入方式
$pdo = DB::connection()->getPdo();
$stmt = $pdo->prepare("INSERT INTO jobs (queue, payload, attempts, reserved_at, available_at, created_at) VALUES (?, ?, ?, ?, ?, ?)");

foreach ($users as $user) {
    // 构建符合Laravel队列规范的payload
    $payload = json_encode([
        'displayName' => ProcessEmail::class,
        'job' => 'Illuminate\Queue\CallQueuedHandler@call',
        'maxTries' => null,
        'timeout' => null,
        'timeoutAt' => null,
        'data' => [
            'commandName' => ProcessEmail::class,
            'command' => serialize(new ProcessEmail($user, $largeEmailBody))
        ]
    ]);

    $stmt->execute([
        'default', // 目标队列名称
        $payload,
        0, // 初始尝试次数
        null,
        now()->getTimestamp(), // 任务可用时间
        now()->getTimestamp() // 任务创建时间
    ]);
}

关键说明

  • 直接使用PDO绕过了Eloquent的事件监听、模型实例管理等环节,避免了日志监听代码触发的内存累积
  • 手动构建队列任务的payload需严格匹配Laravel队列的格式,确保任务能被队列处理器正常消费

内容的提问来源于stack exchange,提问作者Magmatic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 19:42:05