JSONStream.parse() を介して入力ストリーム (巨大な GeoJSON ファイルから作成) をパイプ処理してストリームをオブジェクトに分割し、次に event-stream.map() を介してオブジェクトを変換できるようにし、次に JSONStream を介してパイプしようとしています。 .stringify() を使用して文字列を作成し、最後に書き込み可能な出力ストリームにします。プロセスが実行されると、最終的にヒープを使い果たすまで、ノードのメモリ フットプリントが増加し続けることがわかります。問題を再現する最も単純なスクリプト (test.js) を次に示します。
const fs = require("fs")
const es = require("event-stream")
const js = require("JSONStream")
out = fs.createWriteStream("/dev/null")
process.stdin
.pipe(js.parse("features.*"))
.pipe(es.map( function(data, cb) {
cb(null, data);
return;
} ))
.pipe(js.stringify("{\n\"type\": \"FeatureCollection\", \"features\": [\n\t", ",\n\t", "\n]\n}"))
.pipe(out)
JSON のエンドレス ストリームをノードの process.stdin に吐き出す小さな bash スクリプト (barf.sh) により、ノードのヒープが徐々に大きくなります。
#!/bin/bash
echo '{"type":"FeatureCollection","features":['
while :
do
echo '{"type":"Feature","properties":{"name":"A Street"}, "geometry":{"type":"LineString"} },'
done
次のように実行します。
barf.sh | node test.js
この問題を回避する興味深い方法がいくつかあります。
- fs.createWriteStream() を削除し、最後のパイプ ステージを「.pipe(out)」から「.pipe(process.stdout)」に変更してから、ノードの stdout を /dev/null にパイプします。
- 非同期 es.map() を同期 es.mapSync() に変更します
上記の 2 つのアクションのいずれかにより、ノードのメモリ フットプリントが低く、変更されずに、スクリプトを永久に実行できます。Ubuntu 16.04 を実行する 8 GB の RAM を搭載した 8 コア マシンで、ノード v6.3.1、イベント ストリーム v3.3.4、および JSONStream 1.1.4 を使用しています。
私の側の明らかなエラーであると確信しているものを誰かが修正するのを手伝ってくれることを願っています。