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

Node.js多URL循环请求内存泄漏问题求助及代码排查

内存泄漏问题分析与优化方案

嘿,我帮你排查下这个Node.js脚本的内存泄漏问题,然后给出具体的优化思路和代码!

先说说为啥会内存泄漏

你的脚本主要有这几个核心问题导致内存飙升甚至宕机:

  • 无限制并发请求:每次remoteControllerPress执行都会一次性发起所有URL的请求,要是前一轮的请求还没处理完,6秒后又会发起新的一批,请求越堆越多,大量未释放的HTTP连接、回调上下文占满内存。
  • 用了废弃的request库:request早就停止维护了,本身就存在不少内存泄漏的已知问题,而且对资源的自动清理做得不好。
  • 异步逻辑没闭环:递归式的setTimeout调用,加上没等前一轮所有请求完成就发起下一轮,导致内存里累积大量未完成的异步任务上下文。
  • 错误处理不完整:部分请求失败的分支没做资源清理,可能残留句柄占用内存。

具体优化步骤&代码

下面是优化后的完整方案,我会一步步说明改动点:

1. 替换依赖,用现代HTTP客户端+并发控制

把request换成node-fetch(原生Fetch的Node.js实现,更稳定),再用p-limit限制并发请求数,避免请求堆积。先装依赖:

npm install node-fetch p-limit

2. 重构异步逻辑,确保任务闭环

改用Promise版的fs模块,处理异步操作更清晰;等一轮所有请求都完成后,再发起下一轮调用,避免任务堆积;用path模块处理路径更安全,不会因为拼接出错导致问题。

优化后的完整代码

const fs = require('fs').promises; // 用Promise版fs,异步处理更可控
const path = require('path'); // 安全处理路径拼接
const fetch = require('node-fetch');
const dateTime = require('node-datetime');
const express = require('express');
const pLimit = require('p-limit');
const app = express();

const urls = [
  'http://www.google.com',
  'https://www.bing.com',
  'http://www.yahoo.com',
  'http://stackoverflow.com',
  'http://github.com',
  'http://www.yahoo.co.jp'
];
const concurrencyLimit = 2; // 限制同时跑2个请求,可根据服务器配置调整
const limit = pLimit(concurrencyLimit);

async function remoteControllerPress() {
  const dt = dateTime.create();
  const newCurrentTimeDir = dt.format('Y-m-d-H-M-S').toString();
  const dirName = path.join(__dirname, newCurrentTimeDir); // 用path.join避免路径错误

  // 检查目录是否存在,不存在则创建
  try {
    await fs.access(dirName);
  } catch {
    await fs.mkdir(dirName, { recursive: true }); // 递归创建,即使父目录不存在也能成
  }

  console.log(`==============calling at ${newCurrentTimeDir}\n`);

  // 用p-limit包装请求,限制并发数
  const requestTasks = urls.map(async (url, index) => {
    return limit(async () => {
      try {
        const response = await fetch(url);
        console.log(`---------URL: ${url}`);
        if (response.ok) { // 用response.ok判断请求成功,比直接判断200更全面
          const body = await response.text();
          console.log(`URL: ${url} statusCode: ${response.status}`);
          const filePath = path.join(dirName, `file_${index}`);
          await fs.writeFile(filePath, body);
          console.log(`${filePath} was saved!\n\n`);
        } else {
          console.log(`URL: ${url} failed with status: ${response.status}`);
        }
      } catch (error) {
        console.log(`URL: ${url} error:`, error.code || error.message);
      }
    });
  });

  // 等所有请求都处理完,再发起下一轮
  await Promise.all(requestTasks);
  setTimeout(remoteControllerPress, 6000);
}

console.log("==============running...\n ");
remoteControllerPress();

app.post('/', function (req, res) {
  res.send('hello world');
});

app.listen(3000, () => console.log('Server start listening on port 3000...'));

额外的内存优化小建议

  • 定期清理旧目录:要是脚本长期运行,生成的目录会越来越多,不仅占磁盘,还可能残留未释放的文件句柄,可以加个定时任务,比如删掉7天前的旧目录。
  • 监控内存状态:用node --inspect启动脚本,然后用Chrome DevTools的Memory面板拍内存快照,就能精准定位剩下的内存泄漏点。
  • 调整并发数:根据你的服务器配置,调整concurrencyLimit的值,比如服务器性能好可以调到3-4,性能一般就保持1-2,平衡速度和内存占用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:55:31