【发布时间】:2016-03-22 21:52:41
【问题描述】:
我在节点中有一些代码,基本上它是对外部服务进行 api 调用并将返回的数据转储到数据库中。但是它肯定有一些严重的内存泄漏,因为节点服务器会在中间耗尽内存。我使用的 AWS 实例是 2CPU,4GB RAM。我花了很多时间来弄清楚泄漏在哪里,但还没有运气。以下是代码,任何提示都会有所帮助。
function refreshSitesBy5Min(rawData, callback){
var sites = JSON.parse(rawData).data;
if (typeof sites !== 'undefined' && sites.length > 0){
log.info('refreshing sites 5min');
sites.forEach(function(elem, index, array){
db.site_5min.find({siteid: elem.id, ts : moment(elem.ts).format('YYYY-MM-DDThh:mm:ss')}, function(err, found){
if (typeof found === 'undefined' || found == null || found.length == 0){
db.site_5min.save({
siteid : elem.id,
gran : '5min',
ts : moment(elem.ts).format('YYYY-MM-DDThh:mm:ss'),
wh_sum : elem.Wh_sum
}, function(err, inserted){
if (err){
log.error(err);
}
});
}
else{
db.site_5min.save({
id: found.id,
siteid : elem.id,
gran : '5min',
ts : moment(elem.ts).format('YYYY-MM-DDThh:mm:ss'),
wh_sum : elem.Wh_sum
}, function(err, updated){
if (err){
log.error(err);
}
})
}
})
})
}
else{
log.warn('no sites data');
}
callback();
}
这是调用前一个方法的代码:
function refreshSiteByGran(globalToken, gran, frequency){
log.info('refreshing site for ' + gran + ' table');
// db.site.find({}, function(err, sites){
db.run("select * from site", function(err, sites){
if (err){
log.error(err);
}
if (sites){
function handler(i){
if (i < sites.length){
var thePath = '/v3/sites/' + sites[i].siteid + '/data?fields=Wh_sum&tz=US/Pacific&gran=' + gran;
var end = moment().subtract(1, 'days').format('YYYY-MM-DDThh:mm:ss');
var start;
if (gran === '5min' || gran === 'hourly'){
start = moment(end).subtract(frequency, 'days').format('YYYY-MM-DDThh:mm:ss');
}
else if (gran === 'daily'){
start = moment(end).subtract(frequency, 'days').format('YYYY-MM-DDThh:mm:ss');
}
else if (gran === 'monthly'){
start = moment(end).subtract(frequency, 'months').format('YYYY-MM-DDThh:mm:ss');
}
thePath = thePath + '&start=' + start + '&end=' + end;
log.warn('thePath: ' + thePath);
var options = locusUtil.setOptions(thePath, globalToken.token.access_token);
request(options, function(err, result, body){
if (err){
log.error(err + ' path: ' + thePath);
}
if (body && JSON.parse(body).statusCode == 401){
getLocusToken(function(){
setTimeout(function(){
handler(i);
}, 2000);
})
}
else if (body && JSON.parse(body).statusCode == 200){
var data = JSON.parse(body).data;
// log.info('any data? ' + JSON.stringify(body, null, 4));
if (typeof data !== 'undefined' && data.length > 0){
if (gran === '5min'){
refreshSitesBy5Min(body, function(){
log.info('inserted: ' + data[0].id);
setTimeout(function(){
handler(i+1);
}, 2000);
})
}
if (gran === 'hourly'){
refreshSitesByHourly(body, function(){
log.info('inserted: ' + data[0].id);
setTimeout(function(){
handler(i+1);
}, 2000);
})
}
if (gran === 'daily'){
refreshSitesByDaily(body, function(){
log.info('inserted: ' + data[0].id);
setTimeout(function(){
handler(i+1);
}, 2000);
})
}
if (gran === 'monthly'){
refreshSitesByMonthly(body, function(){
log.info('inserted: ' + data[0].id);
setTimeout(function(){
handler(i+1);
}, 2000);
})
}
}
else{
setTimeout(function(){
handler(i+1);
}, 2000);
}
}
// re-try for concurrency error
else if (body && JSON.parse(body).statusCode == 429){
log.warn('error body ' + JSON.stringify(body));
setTimeout(function(){
handler(i);
}, 2000);
}
// if any other error, just skip
else {
setTimeout(function(){
handler(i+1);
}, 2000);
}
})
}
else{
return;
}
}
handler(0);
}
});
}
我相信问题出在这两个块里面,我用 memwatch 监控 v8 垃圾收集,我看到 usage_trend 增长很快,所以它一定有泄漏。
【问题讨论】:
-
进程是否真的在某个时候崩溃?您是否尝试通过在命令行中添加
--expose-gc并每隔一段时间调用gc();来强制GC? -
是的,它确实崩溃了,并给我错误:致命错误:提交半空间失败。分配失败 - 进程内存不足。既然是内存泄漏,那么 force gc() 应该帮不上什么忙,我想找出哪里是泄漏并删除它
-
数据库代码在哪里?可以发一下吗?
-
db 我正在使用一个名为massage的节点模块,将数据保存到db的实际代码是第一个块
标签: node.js memory-leaks