You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord定时消息机器人JS堆内存溢出问题优化咨询

内存优化步骤

1. 复用DiscordClient实例,避免重复创建销毁

每次定时任务都新建DiscordClient并执行登录/销毁操作,会产生大量临时对象,且销毁过程中容易残留未回收的资源。改为按botToken缓存客户端实例,复用长连接:

// 全局缓存客户端,key为botToken
const clientCache = new Map();

async function getOrCreateClient(setting) {
  const { botToken } = setting;
  if (clientCache.has(botToken)) {
    const client = clientCache.get(botToken);
    // 检查客户端是否就绪,断开则重新登录
    if (!client.client.isReady()) {
      await client.start();
    }
    return client;
  }
  // 新建客户端并缓存
  const client = new DiscordClient(setting);
  await client.start();
  clientCache.set(botToken, client);
  // 客户端断开时自动移除缓存
  client.client.on('disconnect', () => clientCache.delete(botToken));
  return client;
}

修改initializeSettingsAndSendMessage逻辑:

for (const setting of settingsList) {
  try {
    const discordClient = await getOrCreateClient(setting);
    await discordClient.sendMessagesDependsOnSettingId(discordClient.getSettingId());
  } catch (err) {
    console.error(`处理配置 ${setting.id} 失败:`, err);
    clientCache.delete(setting.botToken); // 出错时移除缓存,下次重建
  }
}

2. 彻底清理客户端资源,避免内存泄漏

原stop方法仅调用destroy,需补充缓存清理和引用解除,帮助GC回收内存:

public async stop() {
  if (!this.client) return;
  await this.client.destroy();
  // 解除所有事件监听
  this.client.removeAllListeners();
  // 清空客户端内置缓存
  this.client.guilds.cache.clear();
  this.client.channels.cache.clear();
  this.client.users.cache.clear();
  // 解除引用,让GC可以回收对象
  this.client = null;
}

3. 优化Discord.js缓存策略

Discord.js默认会缓存大量Guild、Channel等对象,可根据需求禁用不必要的缓存,减少内存占用:

创建DiscordClient时调整客户端选项:

class DiscordClient {
  constructor(setting) {
    this.client = new Client({
      intents: [/* 仅保留必要的intents,比如Guilds、GuildMessages */],
      makeCache: Manager.cacheWithLimits({
        GuildManager: 0, // 不需要缓存所有Guild,按需获取
        ChannelManager: { maxSize: 50 }, // 限制频道缓存数量
        MessageManager: 0, // 不需要缓存消息
        UserManager: 0 // 不需要缓存用户
      })
    });
    // ...其他初始化逻辑
  }
}

4. 控制异步操作并发量,避免内存瞬间暴涨

如果settingsList数量较多,并行创建客户端会导致内存瞬间飙升。改为串行处理或限制并发数:

// 串行处理(适合配置数量不多的场景)
async function initializeSettingsAndSendMessage() {
  for (const setting of settingsList) {
    try {
      const discordClient = await getOrCreateClient(setting);
      await discordClient.sendMessagesDependsOnSettingId(discordClient.getSettingId());
    } catch (err) {
      console.error(`处理配置 ${setting.id} 失败:`, err);
      clientCache.delete(setting.botToken);
    }
  }
}

// 限制并发数(适合配置数量多的场景)
const CONCURRENT_LIMIT = 5;
async function initializeSettingsAndSendMessage() {
  const chunks = [];
  for (let i = 0; i < settingsList.length; i += CONCURRENT_LIMIT) {
    chunks.push(settingsList.slice(i, i + CONCURRENT_LIMIT));
  }
  for (const chunk of chunks) {
    await Promise.allSettled(
      chunk.map(async setting => {
        try {
          const discordClient = await getOrCreateClient(setting);
          await discordClient.sendMessagesDependsOnSettingId(discordClient.getSettingId());
        } catch (err) {
          console.error(`处理配置 ${setting.id} 失败:`, err);
          clientCache.delete(setting.botToken);
        }
      })
    );
  }
}

5. 排查内存快照中的泄漏点

结合你生成的内存快照,重点检查:

  • 是否有大量未被回收的DiscordClient、Client实例
  • 是否存在全局变量(如clientCache)持有过多过期引用
  • 是否有未移除的事件监听器(比如客户端的message、ready等事件)

如果发现某类对象持续增长,针对性清理引用或调整逻辑。

6. 可选:定时清理闲置客户端

如果部分机器人长时间未使用,可定时清理缓存中的闲置客户端:

// 每天清理一次超过24小时未使用的客户端
setInterval(() => {
  const now = Date.now();
  for (const [token, client] of clientCache.entries()) {
    if (now - client.lastUsed > 24 * 60 * 60 * 1000) {
      client.stop();
      clientCache.delete(token);
    }
  }
}, 24 * 60 * 60 * 1000);

// 在DiscordClient中添加lastUsed字段,每次发送消息时更新
class DiscordClient {
  constructor(setting) {
    this.lastUsed = Date.now();
    // ...其他初始化
  }

  async sendMessagesDependsOnSettingId(settingId) {
    this.lastUsed = Date.now();
    // ...原发送逻辑
  }
}

内容的提问来源于stack exchange,提问作者s1n

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 18:40:17