# Puppeteer占用内存过高的问题

# 问题描述

  1. 服务器使用的CentOS系统,使用docker安装Puppeteer容器
  2. 使用Express框架搭建服务端,调用Puppeteer库来访问某链接
  3. 调用接口比较频繁,存在并发的情况
  4. 发现运行一段时间后内存占用很高,重启后会降下来
  5. 网上说的创建固定的Browser实例数量以及修改配置方案都无效

# 问题分析

可能是BrowserPage关闭后没有完全释放内存,导致内存可用率降低

# 解决方案

  1. 定时重启

使用linux的crontab定时重启Express服务,这种方案会造成短时间的连接中断及服务不可用

  1. 定时创建和摧毁Browser实例

在代码层实现Browser实例的定时创建和销毁,具体逻辑参考代码

const puppeteer = require("puppeteer");

// Browser实例
let browserList = [];

// 不用的浏览器
let unusedBrowser = [];

// 创建浏览器实例
const createBrowser = async () => {
  
  const browser = await puppeteer.launch({
    headless: true,
    args: [
      "--disable-gpu",
      "--disable-dev-shm-usage",
      "--disable-setuid-sandbox",
      "--no-first-run",
      "--no-sandbox",
      "--no-zygote",
      "--single-process",
    ],
  });

  // 记录该浏览器实例打开的页面数
  let pageCount = 0;

  // 监听到打开了一个新窗口
  browser.on("targetcreated", () => {
    pageCount++;
  });

  // 监听到窗口关闭
  browser.on("targetdestroyed", () => {
    pageCount--;

    if (pageCount === 0 && unusedBrowser.includes(browser)) {
      console.log("命中unusedBrowser");
      delBrowser(browser);
    }
  });

  browserList.push(browser);
};

// 从browserList和unusedBrowser中删除
const delBrowser = (browser) => {
  browserList = browserList.filter((item) => item !== browser);
  unusedBrowser = unusedBrowser.filter((item) => item !== browser);

  browser.close().then(() => {
    browser = null;
    console.log("删除浏览器", browserList.length, unusedBrowser.length);
  });
};

// 始终返回最后一个浏览器实例
const getBrowser = () => {
  return browserList[browserList.length - 1];
};

// 定时任务
const scheduledTask = () => {
  // 每隔20秒去创建一个新的Browser实例,并销毁第一个实例
  setInterval(() => {
    createBrowser().then(() => {
      // 把第一个浏览器置为不可用
      const firstBrower = browserList[0];
      firstBrower.pages().then((pages) => {
        console.log(`第一个浏览器实例打开的页面数为${pages.length}`);

        // 如果当前没有打开的页面,创建Browser实例时会默认初始化一个页面,所以这里判断的是<=1
        if (pages.length <= 1) {
          delBrowser(firstBrower);
        } else {
          unusedBrowser.push(browserList[0]);
        }
      });
    });
  }, 20 * 1000);
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
上次更新时间: 4/4/2022, 9:21:27 PM