gpt4 book ai didi

javascript - Node.js 刮板中的内存泄漏

转载 作者:IT老高 更新时间:2023-10-28 23:17:49 29 4
gpt4 key购买 nike

这是一个用 Node.js 用 Ja​​vaScript 编写的简单抓取工具,用于从 Wikipedia 中抓取元素周期表元素数据。依赖关系是 jsdom用于 DOM 操作和 chain-gang用于排队。

它在大多数情况下都可以正常工作(它不会优雅地处理错误),而且代码也不算太糟糕,我敢说 for 尝试,但它有一个严重的错误 - 它会泄漏内存可怕的是,每个元素占用计算机内存的 0.3% 到 0.6% 不等,因此当它开始领先时,它将使用接近 20% 的地方,这显然是 Not Acceptable 。

我尝试过使用分析器,但要么发现它们没有帮助,要么难以解释数据。我怀疑它与 processElement 的传递方式有关,但我很难将队列代码重写为更优雅的东西。

var fs = require('fs'),
path = require('path'),
jsdom = require("jsdom"),
parseUrl = require('url').parse,
chainGang = require('chain-gang');

var chain = chainGang.create({
workers: 1
});

var Settings = {
periodicUrl: 'http://en.wikipedia.org/wiki/Template:Periodic_table',
periodicSelector: '#bodyContent > table:first',
pathPrefix: 'data/',
ignoredProperties: ['Pronunciation']
};

function writeToFile(output) {
var keys = 0;

// Huge nests for finding the name of the element... yeah
for(var i in output) {
if(typeof output[i] === 'object' && output[i] !== null){
for(var l in output[i]) {
if(l.toLowerCase() === 'name') {
var name = output[i][l];
}
}

keys += Object.keys(output[i]).length;
}
}

console.log('Scraped ' + keys + ' properties for ' + name);
console.log('Writing to ' + Settings.pathPrefix + name + '.json');
fs.writeFile(Settings.pathPrefix + name + '.json', JSON.stringify(output));
}

// Generic create task function to create a task function that
// would be passed to the chain gang
function createTask (url, callback) {
console.log('Task added - ' + url);

return function(worker){
console.log('Requesting: ' +url);

jsdom.env(url, [
'jquery.min.js' // Local copy of jQuery
], function(errors, window) {
if(errors){
console.log('Error! ' + errors)
createTask(url, callback);
} else {
// Give me thy $
var $ = window.$;

// Cleanup - remove unneeded elements
$.fn.cleanup = function() {
return this.each(function(){
$(this).find('sup.reference, .IPA').remove().end()
.find('a, b, i, small, span').replaceWith(function(){
return this.innerHTML;
}).end()
.find('br').replaceWith(' ');
});
}

callback($);
}

worker.finish();
});
}
}

function processElement ($){
var infoBox = $('.infobox'),
image = infoBox.find('tr:contains("Appearance") + tr img:first'),
description = $('#toc').prevAll('p').cleanup(),
headers = infoBox.find('tr:contains("properties")'),
output = {
Appearance: image.attr('src'),
Description: $('.infobox + p').cleanup().html()
};

headers.each(function(){
var that = this,
title = this.textContent.trim(),
rowspan = 0,
rowspanHeading = '';

output[title] = {};

$(this).nextUntil('tr:has(th:only-child)').each(function(){
var t = $(this).cleanup(),
headingEle = t.children('th'),
data = t.children('td').html().trim();

if(headingEle.length) {
var heading = headingEle.html().trim();
}

// Skip to next heading if current property is ignored
if(~Settings.ignoredProperties.indexOf(heading)) {
return true;
}

if (rowspan) {
output[title][rowspanHeading][data.split(':')[0].trim()] = data.split(':')[1].trim();
rowspan--;
} else if (headingEle.attr('rowspan')){
rowspan = headingEle.attr('rowspan') - 1;
rowspanHeading = heading;

output[title][heading] = {};
output[title][heading][data.split(':')[0]] = data.split(':')[1];
} else if (~heading.indexOf(',')){
data = data.split(',');

heading.split(',').forEach(function(v, i){
output[title][v.trim()] = data[i].trim();
});
} else {
output[title][heading] = data;
}
});
});

writeToFile(output);
}

function fetchElements(elements) {
elements.forEach(function(value){
// Element URL used here as task id (second argument)
chain.add(createTask(value, processElement), value);
});
}

function processTable($){
var elementArray = $(Settings.periodicSelector).find('td').map(function(){
var t = $(this),
atomicN = parseInt(t.text(), 10);

if(atomicN && t.children('a').length) {
var elementUrl = 'http://' + parseUrl(Settings.periodicUrl).host + t.children('a:first').attr('href');

console.log(atomicN, t.children('a:first').attr('href').split('/').pop(), elementUrl);
return elementUrl;
}
}).get();

fetchElements(elementArray);
fs.writeFile(Settings.pathPrefix + 'elements.json', JSON.stringify(elementArray));
}

// Get table - init
function getPeriodicList(){
var elementsList = Settings.pathPrefix + 'elements.json';

if(path.existsSync(elementsList)){
var fileData = JSON.parse(fs.readFileSync(elementsList, 'utf8'));
fetchElements(fileData);
} else {
chain.add(createTask(Settings.periodicUrl, processTable));
}
}

getPeriodicList();

最佳答案

jsdom 确实存在内存泄漏,这源于 Node 的 vm.runInContext() 后面的复制输入和复制输出逻辑。一直在努力使用 c++ 解决这个问题,我们希望在尝试将其推送到 Node 之前证明解决方案。

目前的解决方法是为每个 dom 生成一个子进程,并在完成后将其关闭。

编辑:

从 jsdom 0.2.3 开始,只要您在完成后关闭窗口 (window.close()),此问题就已解决。

关于javascript - Node.js 刮板中的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5718391/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com