" JavaScript堆内存不足"流媒体大文件

时间:2017-08-06 00:17:21

标签: javascript node.js mongodb memory

我正在尝试使用XML - > JSON - >我服务器上的MongoDB。我有一个NodeJS应用程序,它流式传输XML,将其转换为JSON,然后将其以1000个块的形式添加到MongoDB服务器。然而,在大约75000条记录之后,我的Macbook的风扇开始旋转得更快,处理速度非常慢。几分钟后,我收到了这个错误:

  

< ---最后几个GC --->

     

[30517:0x102801600] 698057 ms:标记扫描1408.2(1702.9) - > 1408.1(1667.4)MB,800.3 / 0.0 ms(自标记开始以0步开始+ 0.0 ms,最大步0.0 ms,标记开始803 ms后的最长时间)最后的手段   [30517:0x102801600] 698940 ms:标记扫描1408.1(1667.4) - > 1408.1(1667.4)MB,882.2 / 0.0 ms最后的手段

最后在JS stacktrace中:

  

致命错误:CALL_AND_RETRY_LAST分配失败 - JavaScript堆内存不足

我感觉我的内存不多了,但是当文件超过70 GB且我只有16 GB的内存时,用--max-old-space-size(或其他)增加允许的内存不起作用。< / p>

以下是我要做的代码:

var fs = require('fs'),
    path = require('path'),
    XmlStream = require('xml-stream'),
    MongoClient = require('mongodb').MongoClient,
    url = 'mongodb://username:password@my.server:27017/mydatabase',
    amount = 0;

MongoClient.connect(url, function(err, db) {

    var stream = fs.createReadStream(path.join(__dirname, 'motor.xml'));
    var xml = new XmlStream(stream);

    var docs = [];
    xml.collect('ns:Statistik');

    // This is your event for the element matches
    xml.on('endElement: ns:Statistik', function(item) {
        docs.push(item);           // collect to array for insertMany
        amount++;

        if ( amount % 1000 === 0 ) { 
          xml.pause();             // pause the stream events
          db.collection('vehicles').insertMany(docs, function(err, result) {
            if (err) throw err;
            docs = [];             // clear the array
            xml.resume();          // resume the stream events
          });
        }
    });

    // End stream handler - insert remaining and close connection
    xml.on("end",function() {
      if ( amount % 1000 !== 0 ) {
        db.collection('vehicles').insertMany(docs, function(err, result) {
          if (err) throw err;
          db.close();
        });
      } else {
        db.close();
      }
    });

});

我的问题是:我有内存泄漏吗?为什么Node允许代码像这样构建内存?除了为我的电脑购买70多GB的RAM之外,还有其他方法吗?

1 个答案:

答案 0 :(得分:2)

将我的评论作为答案发布,因为它解决了这个问题,并且可能对以这种方式使用xml-stream包进行难以实现的其他人有用。

问题是,collect方法导致了问题,因为它强制解析器在解析时收集数组中已处理节点的所有实例。 collect仅应用于从正在解析的每个节点收集特定类型的子项。默认行为是不这样做(由于解析器的流式特性允许您轻松处理多GB文件)。

因此解决方案是删除该行代码并使用endElement事件。

相关问题