我有一个应用程序,它将大量大但不是巨大的 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