【发布时间】:2015-08-14 09:28:41
【问题描述】:
我生成了一个约 200'000 个元素的对象数组(使用 map 中的对象文字表示法而不是 new Constructor()),并且我将它的 JSON.stringify'd 版本保存到磁盘中占用 31 MB,包括换行符和每个缩进一个空格 (JSON.stringify(arr, null, 1))。
然后,在一个新的节点进程中,我将整个文件读入一个 UTF-8 字符串并传递给JSON.parse:
var fs = require('fs');
var arr1 = JSON.parse(fs.readFileSync('JMdict-all.json', {encoding : 'utf8'}));
根据 Mavericks 的活动监视器,节点内存使用量约为 1.05 GB!在我古老的 4 GB RAM 机器上,即使在终端上打字也感觉比较迟钝。
但是,如果在一个新的节点进程中,我将文件的内容加载到一个字符串中,在元素边界处将其切碎,然后 JSON.parse 每个元素单独进行,表面上得到相同的对象数组:
var fs = require('fs');
var arr2 = fs.readFileSync('JMdict-all.json', {encoding : 'utf8'}).trim().slice(1,-3).split('\n },').map(function(s) {return JSON.parse(s+'}');});
节点只使用了大约 200 MB 的内存,并且没有明显的系统延迟。这种模式在节点的多次重启中仍然存在:JSON.parseing 整个数组占用大量内存,而按元素解析它的内存效率更高。
为什么在内存使用方面存在如此巨大的差异?这是JSON.parse 阻止V8 中有效隐藏类生成的问题吗?如何在不切片和切割字符串的情况下获得良好的内存性能?我必须使用流式 JSON 解析吗?????
为了方便实验,我已将有问题的 JSON 文件放在 Gist 中,请随意克隆它。
【问题讨论】:
-
进程消耗的内存没有意义。从字面上看,您无法基于此推断您的代码内存消耗效率。
-
@zerkms 感谢您指出这一点。我应该注意到,当我尝试第一种方法时,我的系统(4 GB 物理 RAM)实际上感觉比较迟钝:即使在终端输入时我也能分辨出来。
-
嗯。如果我启动
node --expose-gc,运行第一个代码sn -p(用完1 GB内存),然后运行global.gc();大约五十次,节点内存使用量慢慢下降到100~ MB。影响——哇。 -
gist.githubusercontent.com/fasiha/909090f86ab5d9e12985/raw/… 显示“错误:blob 太大”
-
@guest271314 抱歉,Github 不会向您显示原始文件,因为它们太大了,但您可以通过
git clone https://gist.github.com/909090f86ab5d9e12985.git获取 repo。或者如果你只是想看一点 JSON 文件,Github 会显示几千行 gist.github.com/fasiha/909090f86ab5d9e12985/revisions
标签: javascript arrays json node.js parsing