首页 > 解决方案 > 在数组中存储 WebSocket 消息时堆内存不足

问题描述

我正在用 Node.js 编写一个 WebSocket 客户端,并且我想对消息数据执行异步操作(即存储在数据库中),但还要确保消息按照它们的顺序一次操作一个已收到。

为了实现这一点,我将消息推送到我的 onMessage 处理程序中的数组,同时使用调用自身的函数一次将消息从数组中移出。像这样的东西:

const flushQueue = async () => {

  const nextMessage = messageQueue.shift();

  await doSomethingAsync(nextMessage); // i.e. store in db, etc.

  flushQueue();
}

抛开我的系统能否跟上这个问题,这种方法效果很好,只是脚本最终会耗尽堆内存。一个简单的测试表明,将一个元素从数组中移出实际上会增加使用的堆内存量,而我的假设是它减少了使用的内存:

const a = [1,2,3,4,5,6];

a.shift();
a.shift();

console.log(process.memoryUsage());

为什么从数组中删除元素会增加进程使用的内存量?如何以一种内存有效的方式无限期地存储我的一组排队的 WebSocket 消息?

标签: node.jswebsocketheap-memory

解决方案


我几乎可以肯定问题出在你的尾声中,而不是移动数组。Node 和 Javascript 没有适当的尾调用优化。一些统计数据TCO 上的帖子

没有尾调用优化的长时间运行循环最终会耗尽内存。

我会删除这个自定义队列,并直接写入数据库。

SQLite + better-sqlite3驱动程序是一个很好的起点。

// pseudo-code example (not tested)
ws.on('message', function incoming (data) {
  const stmt = db.prepare('INSERT INTO list(message) VALUES(?)')
  const result = stmt.run(data) // synchronous in-process write
  // do something with result or something else
});

推荐阅读