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

时间:2018-01-02 15:53:35

标签: node.js express nodes node-modules node-webkit

请帮帮我, 我想让我的脚本同时访问多个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://stackoverflow.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...')
);

enter image description here

2 个答案:

答案 0 :(得分:1)

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

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

     }

    /*setTimeout(function(){
        remoteControllerPress();
    },6000); <-- remove that */ 
}
console.log("==============running...\n ");
setInterval(remoteControllerPress, 6000); // <- change this

答案 1 :(得分:1)

使用异步运算符执行异步循环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);