node.js 中的长循环泄漏内存

Posted

技术标签:

【中文标题】node.js 中的长循环泄漏内存【英文标题】:long loop in node.js leak memory 【发布时间】:2018-06-12 08:02:43 【问题描述】:

请帮助我, 我想让我的脚本同时访问多个 URL 以获取一些资源。该脚本运行正常,但问题是它泄漏内存并且服务器将关闭。请任何人帮助给我更好的解决方案。谢谢! 请帮助检查以下源代码:

var fs = require('fs');
var request = require('request');
var dir = './';
var dateTime = require('node-datetime');

const express = require('express');
const app = express();

var urls = [
  'http://www.google.com',
  'https://www.bing.com',
  'http://www.yahoo.com',
  "http://***.com",
  "http://github.com",
  "http://www.yahoo.co.jp"
];

var urlLength=urls.length;
function remoteControllerPress()
    var dt = dateTime.create();
    var newCurrentTimeDir = dt.format('Y-m-d-H-M-S').toString();
    var dirName = dir+newCurrentTimeDir;
    if (!fs.existsSync(dirName))
        fs.mkdirSync(dirName);
    
    console.log("==============calling at "+newCurrentTimeDir + '\n');

    for(var i = 0; i<urlLength; i++) 
     (function() 
      var j = i;
      var url = urls[j];
      process.nextTick(function() 


        request(url, function(error, response, body) 
          console.log("---------URL: "+url);
          if (!error && response.statusCode == 200) 
            console.log("URL: " + url + " statusCode: " + response.statusCode);

            fs.writeFile(dirName+"/file_"+j, body.toString(), function(err) 
                if(err) 
                    return console.log(err);
                
                console.log(dirName+"/file_"+ j +" was saved!\n\n");
            ); 


           else if (error) 
            console.log("error.code:", error.code);
          
        );

      );
     )();
    

    setTimeout(function()
        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...')
);

【问题讨论】:

【参考方案1】:

您的 remoteControllerPress 函数似乎有对自身的引用,因为您使用超时递归调用它。因此垃圾收集器无法清理内存。

一个简单(丑陋?)的解决方法应该是使用 setInterval

     

    /*setTimeout(function()
        remoteControllerPress();
    ,6000); <-- remove that */ 

console.log("==============running...\n ");
setInterval(remoteControllerPress, 6000); // <- change this

【讨论】:

感谢 Pierre Mallet 回复我,但是这个解决方案仍然增加了内存。第一次启动内存为 45Mb,然后在每个循环中增加到 105Mb 每 6 秒增加 60Mb 还是在第一次循环后达到 105 然后保持稳定? 它总是增加直到崩溃【参考方案2】:

使用异步操作符做异步循环https://caolan.github.io/async/docs.html

使用 setInterval 和 setImmediate 而不是使用 setTimeout 以便在每次调用时清除上下文

var async = require("async");

function remoteControllerPress()

    var dt = dateTime.create();
    var newCurrentTimeDir = dt.format('Y-m-d-H-M-S').toString();
    var dirName = dir+newCurrentTimeDir;
    if (!fs.existsSync(dirName))
        fs.mkdirSync(dirName);
    
    console.log("==============calling at "+newCurrentTimeDir + '\n');

    // TO do it 5 by 5
    async.eachOfLimit(urls, 5, function(url, i, cb)

       request(url, function(error, response, body) 

          console.log("---------URL: "+url);


          if (!error && response.statusCode == 200) 

            console.log("URL: " + url + " statusCode: " + response.statusCode);

            fs.writeFile(dirName+"/file_"+j, body.toString(), function(err) 
                if(err)
                
                   console.log(err);
                
                console.log(dirName+"/file_"+ j +" was saved!\n\n");

                return cb();
            ); 


          
          else if (error)
          
            console.log("error.code:", error.code);
            return cb();
          
          else
          
            return cb();
          
        );
    , function(err)

        return;

    );



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

setInterval(function()

  setImmediate(remoteControllerPress);

,6000);

【讨论】:

以上是关于node.js 中的长循环泄漏内存的主要内容,如果未能解决你的问题,请参考以下文章

检测代码中的 node.js/javascript 内存泄漏

如何防止 node.js 中的内存泄漏?

Node.js 刮板中的内存泄漏

第1651期如何分析 Node.js 中的内存泄漏

Node.js中的内存泄漏分析

Node.js内存泄漏分析