使用 Node.js 对 JSON 中的字符串大小有限制吗?

Posted

技术标签:

【中文标题】使用 Node.js 对 JSON 中的字符串大小有限制吗?【英文标题】:Is there a limit on the size of a string in JSON with Node.js? 【发布时间】:2014-07-31 23:36:27 【问题描述】:

我的 Node.js 应用程序的一部分涉及从用户接收字符串作为输入并将其存储在 JSON 文件中。 JSON 本身显然对此没有限制,但是 Node 可以处理成 JSON 的文本量有上限吗?

请注意,我使用 MongoDB 或任何其他技术进行实际插入 - 这是本机字符串化并使用 fs 保存到 .json 文件。

【问题讨论】:

您能发布一些您尝试过的代码吗? ECMAScript 根据***.com/questions/4695187/… 没有设置限制,因此它取决于实现和硬件 @BrandonHorst 我还没试过;这完全是准备工作。 我只需要测试一下... 我在 nodeJS 的一个字符串中放入了 1GB 的旋转字符,它需要它。 【参考方案1】:

node.js 中字符串的最大长度由底层 javascript 引擎“V8”定义。在 V8 中,最大长度与堆大小无关。字符串的大小实际上受优化对象布局定义的限制。请参阅https://chromium-review.googlesource.com/c/v8/v8/+/2030916,这是最近(2020 年 2 月)对 V8 中字符串最大长度的更改。提交消息解释了随着时间的推移不同的长度。限制已从大约 256MB 变为 1GB,然后又回到 512MB(在 64 位 V8 平台上)。

【讨论】:

【参考方案2】:

V8(基于 JavaScript 引擎节点构建)直到 非常 最近有一个 hard limit on heap size of about 1.9 GB。

节点 v0.10 卡在旧版本的 V8 (3.14) 上,因为破坏了围绕原生插件的 V8 API 更改。 Node 0.12 将更新到最新的 V8 (3.26),这将破坏许多原生模块,但打开了提高 1.9 GB 堆限制的大门。

就目前而言,单个节点进程可以保留不超过 1.9 GB 的 JavaScript 代码、对象、字符串等组合。这意味着字符串的最大长度小于 1.9 GB。

可以通过使用Buffers 来解决这个问题,它将数据存储在 V8 堆之外(但仍在您的进程的堆中)。只要 JavaScript 变量中的数据永远不会超过 1.9 GB,一个 64 位的 node 构建几乎可以填满你的所有 RAM。


话虽如此,你永远不应该接近这个限制。在处理这么多数据时,您必须将其作为流处理。您一次不应拥有超过几兆字节(最多)的内存。好消息是 node 特别适合处理流数据。

你应该问自己一些问题:

您实际上从用户那里收到了什么样的数据? 为什么要以 JSON 格式存储? 将千兆字节填充到 JSON 中真的是个好主意吗? (答案是否定的。) 数据存储后会发生什么?你的代码会读吗?还有什么?

您发布的问题实际上对于您实际想要完成的任务非常模糊。如需更具体的建议,请使用更多信息更新您的问题。

如果您希望数据永远不会那么大,只需在输入上设置 10 MB 或其他合理的限制,将其全部缓冲,然后使用 JSON.stringify

如果您希望处理更大的数据,则需要将输入直接流式传输到磁盘。如果您需要在数据进入磁盘之前处理/修改数据,请查看transform streams。比如有modules that deal with streaming JSON。

【讨论】:

你不能 JSON.stringify 直接缓冲或任何其他类型的外部存储器,所以它是无关紧要的 @josh 用客户端 javascript 处理超过 5mb 怎么样?我正在尝试发送一个文本区域“文件”来保存游戏中的状态...【参考方案3】:

“vanilla”nodeJS (v0.10.28) 中的最大字符串大小在 1GB 左右。

如果您赶时间,可以使用自加倍字符串测试支持的最大字符串大小。测试的系统有 8GB 的​​ RAM,大部分未使用。

x = 'x';
while (1) 
     x = ''+x+x; // string context
     console.log(x.length);


2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
16384
32768
65536
131072
262144
524288
1048576
2097152
4194304
8388608
16777216
33554432
67108864
134217728
268435456
536870912
FATAL ERROR: JS Allocation failed - process out of memory
Aborted (core dumped)

在另一个测试中,我达到了 1,000,000,000,每次只有一个字符的 for 循环。

现在批评者可能会说,“等等,JSON 怎么样。问题是关于 JSON!”我会大喊在 JAVASCRIPT 中没有 JSON 对象,JS 类型是对象、数组、字符串、数字等......由于 JSON 是字符串表示,这个问题归结为允许的最长字符串是什么。但为了仔细检查,让我们添加一个 JSON.stringify 调用来处理 JSON 转换。

代码

x = 'x';
while (1) 
     x = ''+x+x; // string context
     console.log(JSON.stringify(a:x).length);

期望:JSON 字符串的大小开始大于 2,因为第一个对象将字符串化为 '"a":"xx"' 10 个字符。在属性 a 中的 x 字符串变大之前,它不会开始加倍。它可能会在 256M 左右失败,因为它可能会在字符串化中创建第二个副本。回想一下,字符串化是独立于原始对象的。

结果:

10
12
16
24
40
72
136
264
520
1032
2056
4104
8200
16392
32776
65544
131080
262152
524296
1048584
2097160
4194312
8388616
16777224
33554440
67108872
134217736
268435464

和预想的差不多……

现在这些限制可能与nodeJS项目中实现JS的C/C++代码有关,此时我相信它与Chrome浏览器中使用的V8代码相同。

博客文章中有证据表明人们重新编译 nodeJS 以绕过旧版本中的内存限制。还有许多 nodejs 命令行开关。我还没有测试过任何这样的效果。

【讨论】:

是的,遗憾的是 NodeJS 被限制在 ~500MB 或 1.5GB,具体取决于它的编译方式。 关于重新编译节点的博文不再适用。该帖子引用了使用 V8 3.10 编译节点 v0.6。 Node v0.10 附带 V8 3.14。 @josh3736 谢谢,我会删除它。如果您看到适用的内容,请告诉我或进行编辑。【参考方案4】:

这是一个很好的问题,但我认为您需要担心的上限不涉及最大 JSON 字符串大小。

在我看来,您需要担心的限制是您希望在处理用户请求时阻止请求线程多长时间。

任何大小超过 1MB 的字符串都需要用户几秒钟才能上传,而 10 兆字节可能需要几分钟。服务器收到请求后,需要几百毫秒到几秒的时间才能解析成数据结构,导致用户体验很差(解析 JSON非常开销很大)

带宽和服务器处理时间将掩盖 JSON 可能对字符串大小的任何限制。

【讨论】:

我会把传输限制放得大一点,但瓶颈变成了 JSON 字符串客户端的解析,它是 cpu 密集型的,可以锁定 UI,而且速度很慢,尤其是在一个旧手机或平板电脑。

以上是关于使用 Node.js 对 JSON 中的字符串大小有限制吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Node.js 中使用流对大型嵌套对象进行 JSON 字符串化?

Node.js 中的 JSON 数组

Node.js 如何解析 Array-JSON 中的字符串?

在 Node.js 中使用 BigQuery 将 JSON 作为字符串导入

对 Node.js 的 xml 到 json 有啥建议吗?

如何在Node.js中对使用promises和事件发射器的函数进行单元测试?