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

加密货币实时价格获取致服务器内存占满的优化方案问询

实时加密货币价格获取服务内存占用过高的优化方案

问题背景

我开发了一套实时获取加密货币价格的服务:从CoinGecko API获取大部分代币价格,针对BTC、ETH、XRP则通过PancakeSwap工厂合约+WebSocket ticker获取。因交易平台需求,服务需要每6秒执行一次价格拉取,但运行一段时间后服务器内存会被占满。之前代码的时间复杂度是O(n²),优化后内存占用有所下降,但仍需进一步优化。想请教:

  1. 是否需要在服务器端做主动内存清理?
  2. 当前代码层面还有哪些可优化的点?

优化后代码片段

// Process each token periodically
const processTokens = async () => {
  try {
    for (const token of TOKENS) {
      const priceData = await liquidityContract.methods
        .getPrice([token.address, token.address])
        .call();
      const _openprice = parseFloat(priceData.price) / 10 ** 8;

      if (["ETH", "BTC", "XRP"].includes(token.symbol)) {
        // Special handling for ETH, BTC, and XRP
        client.ws.ticker(token.symbol + "USDT", (ticker) => {
          feed = formatFeedFromTicker(ticker, _openprice);
          updatePriceFeed(token, feed, callsendprice, tokenDatas);
        });
      } else {
        // General handling for other tokens
        if (
          !apiCache[token.coinid] ||
          Date.now() - apiCache[token.coinid].timestamp > CACHE_DURATION
        ) {
          const response = await fetch(
            `https://pro-api.coingecko.com/api/v3/coins/markets?vs_currency=usd&ids=${token.coinid}&order=market_cap_desc&per_page=1&page=1&sparkline=false&x_cg_pro_api_key=${config.CG_KEY}`
          );
          if (!response.ok) continue;
          const data = await response.json();
          if (data.length === 0) continue;
          apiCache[token.coinid] = {
            data: data[0],
            timestamp: Date.now(),
          };
        }
        const feed = formatFeedFromAPI(
          _openprice,
          apiCache[token.coinid].data
        );
        updatePriceFeed(token, feed, callsendprice, tokenDatas);
      }
    }

    if (broadcastMessage) {
      broadcastMessage({ tokenData: tokenDatas });
    }
  } catch (error) {
    console.error("Error in processTokens: ", error);
  } finally {
    // Schedule the next run
    setTimeout(processTokens, 2000);
  }
};
// Start the process
processTokens();
// Transaction checking
if (calltx) {
  monitorTransactions(callbacktx);
}
};

核心优化方案

一、代码层面优化点

1. 修复WebSocket订阅泄漏(关键内存泄漏点)

每次processTokens执行时,都会给BTC/ETH/XRP新增WebSocket订阅回调,但旧订阅从未取消,导致连接、回调函数持续累积,内存不断上涨。

  • 修复:维护订阅映射,每次处理前取消旧订阅再创建新订阅,或复用订阅仅更新价格基准
// 全局维护订阅实例映射
const wsSubscriptions = new Map();

// 替换原BTC/ETH/XRP处理逻辑
if (["ETH", "BTC", "XRP"].includes(token.symbol)) {
  const symbolPair = token.symbol + "USDT";
  // 清理旧订阅
  if (wsSubscriptions.has(symbolPair)) {
    wsSubscriptions.get(symbolPair).unsubscribe();
    wsSubscriptions.delete(symbolPair);
  }
  // 创建新订阅并保存实例
  const subscription = client.ws.ticker(symbolPair, (ticker) => {
    feed = formatFeedFromTicker(ticker, _openprice);
    updatePriceFeed(token, feed, callsendprice, tokenDatas);
  });
  wsSubscriptions.set(symbolPair, subscription);
}

2. 避免异步任务叠加

当前用finally里的setTimeout调度下一次执行,若异步操作(API请求、合约调用)耗时超过2秒,会导致多个processTokens实例并行运行,内存堆积大量未完成的Promise和请求上下文。

  • 修复:确保前一次执行完成后再调度下一次
try {
  // ... 原逻辑 ...
  // 所有异步操作完成后再调度下一次
  setTimeout(processTokens, 2000);
} catch (error) {
  console.error("Error in processTokens: ", error);
  // 出错时仍调度下一次,避免服务中断
  setTimeout(processTokens, 2000);
}
// 移除finally中的setTimeout

3. 新增缓存清理机制

apiCache只添加不清理,若代币从TOKENS列表移除,对应缓存会永久占用内存。

  • 优化:定期清理过期缓存
// 在processTokens开头添加清理逻辑
const now = Date.now();
for (const [coinId, cacheEntry] of Object.entries(apiCache)) {
  // 清理超过缓存有效期2倍的条目
  if (now - cacheEntry.timestamp > CACHE_DURATION * 2) {
    delete apiCache[coinId];
  }
}

4. 并行化合约调用提升效率

原for...of循环串行执行合约调用,代币数量多时单次执行时间过长,加剧任务叠加问题。

  • 优化:用Promise.all批量并行处理合约调用
// 替换原循环中的合约调用部分
const tokenPricePromises = TOKENS.map(async (token) => {
  const priceData = await liquidityContract.methods.getPrice([token.address, token.address]).call();
  return { token, _openprice: parseFloat(priceData.price) / 10 ** 8 };
});
const tokenPriceResults = await Promise.all(tokenPricePromises);

// 遍历并行结果处理代币
for (const { token, _openprice } of tokenPriceResults) {
  // 原有的BTC/ETH/XRP和其他代币处理逻辑
}

二、服务器端内存清理说明

Node.js自带自动垃圾回收机制,无需手动做内存清理。内存持续上涨的核心原因是代码存在资源泄漏(如未释放的WebSocket订阅、定时器),优先解决代码层面的泄漏问题比服务器端手动清理更有效。

若需定位泄漏点,可定期用process.memoryUsage()输出内存状态,或用Chrome DevTools的堆快照工具分析内存占用情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 08:05:54