1

我有一个应用程序,它将大量大但不是巨大的 JSON 对象写入输出文件。对象被创建、写入,然后被丢弃(即我不会将它们全部保留)。我正在使用JSONStream试图使内存使用成为非问题,但它不起作用。

这是一个简单的示例,显示了我遇到的问题:

let fs = require('fs');
let JSONStream = require('JSONStream');

const testfile = 'testfile.json';
const entcount = 70000;
const hacount = 10*1024;

console.log(`opening ${testfile}`);
let outputTransform = JSONStream.stringify();
let outputStream = fs.createWriteStream(testfile);
outputStream.on('finish', () => console.log('finished'));
outputTransform.pipe(outputStream);

console.log(`writing ${entcount} entries, data size ${hacount*2}`);
for (let n = 0; n < entcount; ++ n) {
    let thing = {
        index: n,
        data: 'ha'.repeat(hacount)
    }
    outputTransform.write(thing);
}

console.log('finishing');
outputTransform.end();

此示例使用 JSONStream 将 70000 个对象(每个大约 20kB)流式传输到一个文件(这在我的实际应用程序的范围内)。但是,它在 45000 左右内存不足(帖子末尾的完整输出):

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaS
cript heap out of memory
 1: 0092D8BA v8::internal::Heap::PageFlagsAreConsistent+3050

另外我注意到,当我调用outputTransform.write时,文件大小保持在 0(在上述 OOM 之后也是 0)。outputTransform.end在被调用之前它不会开始增长。所以我假设输出数据正在某处缓冲并且正在吃掉堆。

预期的行为outputTransform.write会导致输出立即被写入,或者至少缓冲在一个可管理大小的缓冲区中;因此我可以编写任意数量的对象,而不必担心 OOM。

所以我的问题是,有没有办法让 JSONStream 不在内存中保存所有这些数据?

增加堆大小并不是一个真正的选择,因为它仍然存在内存限制的上限。


完整输出:

$ node index.js

opening testfile.json
writing 70000 entries, data size 20480

<--- Last few GCs --->

[22256:022DA970]     4589 ms: Mark-sweep 918.8 (924.6) -> 918.3 (921.9) MB, 30.6
 / 0.0 ms  (+ 69.8 ms in 33 steps since start of marking, biggest step 9.7 ms, w
alltime since start of marking 104 ms) (average mu = 0.116, current mu = 0.082)
finalize increm[22256:022DA970]     4593 ms: Scavenge 920.2 (921.9) -> 918.1 (92
6.1) MB, 2.3 / 0.0 ms  (average mu = 0.116, current mu = 0.082) allocation failu
re

<--- JS stacktrace --->

==== JS stack trace =========================================

    0: ExitFrame [pc: 00DDCB97]
Security context: 0x1c200469 <JSObject>
    1: /* anonymous */ [0D080429] [index.js:~1] 
[pc=203C4C90](this=0x0d0804c5 <Object map = 1ED0021D>,0x0d0804c5 
<Object map = 1ED0021D>,0x0d0804a5 <JSFunction require (sfi = 3025687D)>,
0x0d08045d <Module map = 1ED204A5>,0x3024f3c1 <String[#59]: index.js>,0x0d080449 
<...

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaS
cript heap out of memory
 1: 0092D8BA v8::internal::Heap::PageFlagsAreConsistent+3050
4

0 回答 0