7

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

 3 years ago
source link: https://www.v2ex.com/t/817190
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

V2EX  ›  Node.js

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

  msmmbl · 7 小时 12 分钟前 · 199 次点击

有一个实时应用,使用 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 变量可能会导致泄露。但还是没想明白怎样才会发生这个泄露。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK