使用Chrome Headless批量打印:生成PDF报告后进程未终止
兄弟,我之前也踩过这个Chrome Headless进程泄漏的大坑!这玩意儿要是不管,服务器内存分分钟被榨干,给你分享几个我亲测有效的解决办法:
显式调用关闭逻辑,别依赖自动回收
绝大多数情况下,问题出在代码没主动关闭浏览器实例。比如用Puppeteer的话,用完后必须调用browser.close(),而且要确保这个逻辑无论成功失败都能执行到——哪怕中间抛异常也要在finally块里处理。举个实际代码例子:const puppeteer = require('puppeteer'); async function generatePDF() { let browser; try { browser = await puppeteer.launch({ headless: 'new' }); // 推荐用新版headless模式 const page = await browser.newPage(); await page.goto('https://example.com'); const pdf = await page.pdf(); return pdf; } catch (err) { console.error('生成PDF出错:', err); throw err; } finally { if (browser) { await browser.close(); // 兜底关闭,绝不遗漏 } } }如果是直接调用Chrome命令行生成PDF,执行完一定要主动给对应进程发终止信号(比如
SIGTERM或SIGKILL),别等着系统慢悠悠回收。用进程池复用Chrome实例,减少重复创建
每次请求都开新Chrome进程太浪费了,不如整个进程池复用实例。比如用puppeteer-cluster这类库,它会帮你管理固定数量的Chrome实例,自动分配任务,用完放回池子,进程数量直接可控,不会随便爆炸。添加Chrome启动参数,限制资源+避免异常挂起
启动Chrome时加几个参数能减少进程异常概率:--no-sandbox:部分服务器环境必须加才能运行,同时降低进程开销(生产环境要结合安全需求评估)--disable-dev-shm-usage:避免/dev/shm空间不足导致进程卡死--single-process:强制Chrome单进程运行(会牺牲一点性能,但能大幅减少进程数量)
另外给任务加超时限制,比如Puppeteer的timeout参数,防止某个任务卡住导致进程一直挂着。
排查代码里的资源泄漏点
有时候是异步逻辑没处理好,导致browser.close()根本没执行。比如有没有漏掉await?或者在异步流程中提前返回,跳过了关闭步骤?一定要仔细走一遍代码的执行路径,确保关闭逻辑100%被触发。加兜底的进程监控与清理机制
实在不行就搞个兜底方案:定时扫描系统中长时间运行的Chrome Headless进程(比如超过10分钟的),直接杀掉。Linux上可以用脚本定期执行:pkill -f "chrome --headless=new"或者在代码里加定时器,定期检查未关闭的浏览器实例,强制关闭。
升级Chrome和依赖库到最新版
有些进程无法终止的问题是Chrome旧版本的Bug导致的,比如早期Headless模式的内存泄漏问题。升级到最新稳定版Chrome,同时把Puppeteer这类依赖库也更到最新,很多奇怪的进程问题会自动消失。
内容的提问来源于stack exchange,提问作者Luca Ligios

