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

长时间运行Puppeteer脚本后浏览器内存耗尽问题求助

Puppeteer长时间运行内存泄漏问题分析与解决方案

一、你的标签页处理方式确实可能引发内存泄漏

从代码片段来看,当前的实现存在几个内存泄漏风险点:

  • 每次循环都创建targetcreated监听的Promise,如果某次操作未触发新标签页,这个Promise会一直处于pending状态,占用内存
  • 关闭标签页后,页面对象(newTab/newNewTab)未主动解除引用,V8垃圾回收器可能无法及时回收这些对象
  • 频繁创建新标签页时,浏览器可能残留未释放的DOM节点、事件监听器或网络连接,累计后导致内存占用飙升

二、针对长时间任务的Puppeteer优化实践

1. 标签页管理优化

  • 复用标签页而非频繁创建销毁:固定一个专门的下载标签页,每次导航到PDF链接后清理页面,避免反复创建新标签
  • 关闭标签后强制解除引用:手动将页面对象置为null,帮助垃圾回收:
    await newNewTab.close();
    newNewTab = null; // 解除引用
    await newTab.close();
    newTab = null;
    
  • 替换targetcreated监听逻辑:不要依赖全局监听新标签,改用更可控的方式,比如通过page.evaluate点击元素并获取PDF URL,再用同一个标签页导航下载,减少标签创建次数

2. 启动参数优化(大幅降低内存占用)

启用无头模式+限制浏览器资源,是长任务的核心优化:

const browser = await puppeteer.launch({
  headless: 'new', // Puppeteer v19+新无头模式,比旧模式省内存
  defaultViewport: null,
  args: [
    '--no-sandbox',
    '--disable-setuid-sandbox',
    '--disable-dev-shm-usage', // 避免/dev/shm内存不足问题
    '--disable-gpu',
    '--no-first-run',
    '--single-process', // 单进程模式,减少内存开销(部分功能受限,按需启用)
    '--max-old-space-size=8192', // 限制Node.js堆内存为8GB
    '--memory-pressure-off' // 关闭浏览器内存压力自动冻结逻辑
  ]
});

3. 内存回收与周期清理

  • 定期强制垃圾回收:启动Node时添加--expose-gc参数,在每次日期循环结束后触发:
    if (global.gc) {
      global.gc();
    }
    
  • 定期重启浏览器:不要长期复用同一个浏览器实例,比如每处理10天的数据就重启一次,彻底释放内存:
    if (dateProcessCount % 10 === 0) {
      await browser.close();
      browser = await puppeteer.launch({/* 启动参数 */});
      page = await browser.newPage();
      // 重新执行登录逻辑
    }
    
  • 清理页面缓存:每次分页处理后,清除本地存储和Cookie:
    await page.deleteCookie();
    await page.evaluate(() => {
      window.localStorage.clear();
      window.sessionStorage.clear();
    });
    

4. 下载逻辑优化

  • 绕过浏览器直接下载PDF:如果能拿到PDF的直接URL,用Node.js的axios/fetch直接下载,完全节省浏览器标签的内存开销:
    const axios = require('axios');
    const fs = require('fs');
    
    // 带上登录后的Cookie确保权限
    const pdfStream = await axios.get(pdfUrl, {
      responseType: 'stream',
      headers: { Cookie: await page.cookies().map(c => `${c.name}=${c.value}`).join('; ') }
    });
    pdfStream.data.pipe(fs.createWriteStream(`./pdfs/${filename}.pdf`));
    
  • 配置浏览器直接下载不预览:如果必须用浏览器下载,设置下载路径避免预览渲染:
    await page.setDownloadBehavior({
      behavior: 'allow',
      downloadPath: './pdfs'
    });
    

5. 代码结构优化

  • 拆分嵌套逻辑:将分页处理、PDF下载拆成独立异步函数,减少闭包导致的内存泄漏
  • 清理事件监听器:如果手动添加了浏览器/页面的事件监听,用完后必须移除:
    // 示例:添加监听后记得移除
    const targetHandler = (target) => resolve(target);
    browser.on('targetcreated', targetHandler);
    // 操作完成后移除
    browser.off('targetcreated', targetHandler);
    

三、额外排查点

  • 监控内存使用:每分钟打印内存情况,定位内存增长阶段:
    setInterval(() => {
      const mem = process.memoryUsage();
      console.log(`当前堆内存占用: ${(mem.heapUsed / 1024 / 1024).toFixed(2)} MB`);
    }, 60000);
    
  • 检查CSV写入逻辑:确保分批写入磁盘,不要把大量数据累积在内存中
  • 捕获浏览器端日志:查看是否有内存相关警告:
    page.on('console', msg => console.log(`浏览器日志: ${msg.text()}`));
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 17:33:37