server.js 中的内存泄漏 | 反应/表达/SSR

Fel*_*iel 6 garbage-collection memory-leaks node.js express reactjs

我正在运行一个在 Nodejs 服务器上呈现的 React 应用程序。几天后我发现nodeJs进程的内存随着访问者的数量而增加。每次重新加载页面时,内存使用量都会增加一点。开始时,该过程大约需要 60MB 内存。几天后,它增加到约 450MB。现在我正在重新启动节点进程来解决这个问题。

我认为这是我的 React 设置的问题。即使我只渲染一个非常小的应用程序,我也会遇到泄漏。例子:

// Express server
app.get('*', async (req, res, next) => {
  try {
    const html = ReactDOM.renderToStaticMarkup(
      <html>
        <head />
        <body>
          <h1>hello</h1>
        </body>
      </html>,
    );
    res.status(200);
    res.send(`<!doctype html>${html}`);
  } catch (err) {
    next(err);
  }
});
Run Code Online (Sandbox Code Playgroud)

为了检查内存泄漏,我每 3 秒强制进行一次垃圾回收,并在使用autocannon发出数千个请求时打印出内存使用情况。这给出了以下结果:

Program is using 16234160 bytes of Heap. // Start, no requests yet
Program is using 16177744 bytes of Heap.
Program is using 16177864 bytes of Heap.
Program is using 15185808 bytes of Heap. // Idle heap
Program is using 15185808 bytes of Heap.
Program is using 15185808 bytes of Heap.
Program is using 15185808 bytes of Heap.
Program is using 19199696 bytes of Heap. // Beginning of first 10k requests
Program is using 20890376 bytes of Heap.
Program is using 20201600 bytes of Heap. // New idle heap
Program is using 20201600 bytes of Heap.
Program is using 20201600 bytes of Heap.
Program is using 20201600 bytes of Heap.
Program is using 21761368 bytes of Heap. // Beginning of second 10k requests
Program is using 23862168 bytes of Heap.
Program is using 25191168 bytes of Heap.
Program is using 24731176 bytes of Heap.
Program is using 24512424 bytes of Heap. // New idle heap
Program is using 24512424 bytes of Heap.
Program is using 24512424 bytes of Heap.
Run Code Online (Sandbox Code Playgroud)

当我渲染“真正的”React 应用程序时,内存使用量当然会大幅增加。以下屏幕截图显示了首次启动应用程序和对页面的单个请求之间的差异:

比较

如果我只返回一个没有 React 的字符串,renderToStaticMarkup问题就消失了(例如res.send("<!doctype html><html><head /><body><h1>hello</h1></body></html>");.

我在这里错过了什么吗?或者有一个已知的问题吗?或者这可能是一个明确的问题?

我正在节点上运行v8.4.0,这是我的依赖项(我正在使用react-starter-kit):

"dependencies": {
    "@babel/polyfill": "^7.0.0-beta.44",
    "bluebird": "^3.5.1",
    "body-parser": "^1.18.2",
    "classnames": "^2.2.5",
    "cookie-parser": "^1.4.3",
    "core-js": "^2.5.4",
    "express": "^4.17.1",
    "express-http-proxy": "^1.1.0",
    "express-jwt": "^5.3.1",
    "history": "^4.7.2",
    "intl": "^1.2.5",
    "isomorphic-fetch": "^2.2.1",
    "isomorphic-style-loader": "^4.0.0",
    "node-fetch": "^2.1.2",
    "normalize.css": "^8.0.0",
    "pretty-error": "^2.1.1",
    "prop-types": "^15.6.1",
    "react": "^16.9.0",
    "react-dom": "^16.9.0",
    "react-helmet": "^5.2.0",
    "react-slick": "0.23.1",
    "serialize-javascript": "^1.4.0",
    "smoothscroll-polyfill": "^0.4.4",
    "source-map-support": "^0.5.4",
    "universal-router": "^6.0.0",
    "whatwg-fetch": "^2.0.4"
  },
Run Code Online (Sandbox Code Playgroud)

Fel*_*iel 3

我做了一些更多的测试,发现当我在development(调试)模式下构建应用程序时,泄漏消失了。经过一番调查后,我发现这个 babel 插件仅在以下模式下加载到我的 webpack 文件中productionhttps ://babeljs.io/docs/en/babel-plugin-transform-react-constant-elements

删除该插件后,内存泄漏就消失了。我想这个插件应该只为客户端应用程序加载,因为该插件的作用是

“将 React JSX 元素视为值类型并将它们提升到最高范围”

由于当您关闭页面/选项卡时,客户端应用程序的范围消失了,这并不是什么大问题,但在节点服务器上,它会导致内存随着每个请求而累积。