我对这种类型的JavaScript还是个初学者,所以我会简要解释一下:
我有一个基于Nodejs
的Web爬虫,可以收集(相当多的)数据,并使用Cheerio
(基本上是Node
的jQuery
)处理数据,然后创建一个对象并将其上传到mongoDB。
它完全正常运行,只是在处理更大的网站时会出现问题。似乎正在发生的情况是:
- 我给爬虫提供一个在线商店的URL进行爬取
- Node访问该URL,然后检索从5,000到40,000个产品URL进行抓取
- 对于每个新的URL,Node的
request
模块获取页面源代码然后将数据加载到Cheerio
中。 - 使用Cheerio创建代表该产品的JS对象。
- 我将这个对象发送到MongoDB,然后保存到我的数据库中。
就像我说的那样,它会处理成千上万个URL,一旦达到,比如10,000个URL被加载时,就会在node中出现错误。最常见的错误是:
Node: Fatal JS Error: Process out of memory
好的,这里是实际的问题:
我认为这是因为Node的垃圾清理没有正常工作。可能是因为从所有40,000个URL中爬取的request
数据仍然存储在内存中,或者至少创建的40,000个JavaScript对象可能仍然存在于内存中。也许这还因为MongoDB连接在会话开始时被建立并且从未关闭(只有当所有产品都完成后才手动关闭脚本)。这是为了避免每次记录新产品时都需要打开/关闭连接。
为了确保它们真正被正确清理(一旦产品进入MongoDB,我就不再使用它,并且可以从内存中删除),我能否/应该只需简单地从内存中删除它,使用delete product
?
更重要的是(我显然不太了解JS如何处理对象),如果我删除对象的一个引用,它是否完全从内存中删除,还是我必须删除所有引用?
例如:
var saveToDB = require ('./mongoDBFunction.js');
function getData(link){
request(link, function(data){
var $ = cheerio.load(data);
createProduct($)
})
}
function createProduct($)
var product = {
a: 'asadf',
b: 'asdfsd'
// there's about 50 lines of data in here in the real products but this is for brevity
}
product.name = $('.selector').dostuffwithitinjquery('etc');
saveToDB(product);
}
// In mongoDBFunction.js
exports.saveToDB(item){
db.products.save(item, function(err){
console.log("Item was successfully saved!");
delete item; // Will this completely delete the item from memory?
})
}
mongoDBFunction.js
和主脚本中将变量设置为null
,在它被发送到saveToDB()
函数之后?让我感到困惑的是对象的传递方式,我试图弄清楚实际上有多少个数据的“副本”。 - JVGnull
。垃圾回收器(在给定周期内运行)会处理这些事情。除非 DB 或cheerio
库正在缓存或存储内存中的内容,或者除非您正在将所有数据累积到自己的数组中,否则我猜您可能需要手动运行 GC。我首先会尝试手动运行 GC。如果那样不起作用,那么使用其中一个工具,它将向您显示正在使用内存的对象。 - jfriend00global.gc();
? - JVGglobal.gc()
)。例如,你可以在处理200个URL时运行它。不要过于频繁地调用它,因为这会减慢速度,但显然也不能等太久,否则内存可能会积累并等待被释放。如果您想确定确切的运行频率,则需要进行一些内存分析。关键在于每隔几百个URL就运行它,并查看您的内存使用问题是否得到解决(或变得更好)。然后,您可以考虑优化如何调用它的频率。 - jfriend00