帮忙分析下这段 nodejs 代码的内存泄漏原因

2021-11-22 17:44:44 +08:00
 msmmbl

有一个实时应用,使用 nodejs 编写,会每隔一段时间调用远程 grpc ,大概每秒 1 、2 次这样的调用。上线一个月后发现服务器内存占用越来越大。大概占用了 14GB 的内存吧。用 iotop 发现 node 内存炸了。

使用了 alinode dump heap 了,发现了有一个 promisifyCall 占用了大量内存,疑似泄露。

调用链是

自身大小(字节) 总大小(字节)      函数
0              524600         processTicksAndRejections   internal/process/task_queues.js
0              524600           updateStatus              我自己的文件
0              524600              publish                这里调用了 grpc 导出的函数
524600         524600                promisifyCall        这里应该就是泄露的函数了

promisifyCall 来自于 https://github.com/bojand/promisify-call ,看了下是被 grpcCaller 引用的 https://github.com/bojand/grpc-caller 。项目中使用了 grpcCaller 去调用 grpc 方法。

const res = await grpcCallerInstance.publish(req);

接着这个 publish 操作就走到promisifyCall中去了

promisifyCall 的定义看了下,https://github.com/bojand/promisify-call/blob/master/index.js

const wc = require('with-callback')

/**
 * Promisifies the call to <code>fn</code> if appropriate given the arguments.
 * Calls the function <code>fn</code> either using callback style if last argument is a function.
 * If last argument is not a function, <code>fn</code> is called returning a promise.
 * This lets you create API that can be called in either fashions.
 * @param  {Object}   ctx  context / this
 * @param  {Function} fn   The function to call
 * @param  {arguments}   args Arguments
 * @return {undefined|*|Promise}  Promise if promisified
 */
function promisifyCall (ctx, fn) {
  const args = []
  args.push.apply(args, arguments)
  args.splice(0, 2)
  // check if last (callback) argument is being pased in explicitly
  // as it might be undefined or null, in which case we'll replace it
  const same = fn.length && args.length === fn.length
  const lastIndex = same ? fn.length - 1 : args.length - 1
  const lastArg = args && args.length > 0 ? args[lastIndex] : null
  const cb = typeof lastArg === 'function' ? lastArg : null

  if (cb) {
    return fn.apply(ctx, args)
  }

  return wc(callback => {
    same
      ? args[lastIndex] = callback
      : args.push(callback)
    fn.apply(ctx, args)
  })
}

隐约感觉里面的 args 变量可能会导致泄露。但还是没想明白怎样才会发生这个泄露。

4136 次点击
所在节点    Node.js
3 条回复
msmmbl
2021-11-22 18:04:12 +08:00
我可能搞错了,524600 字节并不大。再抓一晚上数据看看。
zhzbql
2021-11-22 18:07:24 +08:00
Node.js 不用 buffer 不是最大内存 1.4GB 吗,兄弟你这 14GB 怎么搞出来的
msmmbl
2021-11-22 18:14:29 +08:00
@zhzbql 同时起了多个进程

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/817190

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX