大きいが巨大ではない 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 を使用して、それぞれ約 20kB の 70000 個のオブジェクトをファイルにストリーミングします (これは、実際のアプリケーションの範囲内です)。ただし、約 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