提问人:Steve Clay 提问时间:5/4/2023 最后编辑:Steve Clay 更新时间:5/9/2023 访问量:87
在像 V8 这样的 JavaScript 引擎中,对象是否比返回它的函数消耗更多的内存?
In a JavaScript engine like V8, does an object consume more memory than a function that returns it?
问:
假设我有一个不平凡的静态数据结构:
[
{ id: 1, title: 'Long title 1...' },
{ id: 2, title: 'Long title 2...' },
/* 998 more... */
]
考虑到我的应用程序很少需要映射/过滤它(我假设将模块保留在内存中),它是否会消耗更少的内存来 (A) 将其导出为 const:
export const rows = [ ... ];
或者 (B),导出一个返回文本的函数:
export function getRows() {
return [ ... ];
}
或者 (C),导出一个 JSON.parse 字符串文字的函数?
export function getRows() {
return JSON.parse("[ ... ]");
}
需要明确的是,在页面生命周期的长度内,它对浏览器选项卡的 RAM 消耗的贡献。在不频繁操作期间,RAM 使用率的瞬时峰值不太令人担忧。
我知道在(B)和(C)中,每次调用都可能会产生一些对象构造时间,但这并不像占用RAM那样令人担忧。我知道 (C) 延迟了文字的解析时间,但目前尚不清楚解析后的表示是否比其 JSON 字符串文字消耗更多的 RAM。
答:
简短的回答可能是“是”。从我在此存储库中执行的测试来看,“获胜者”是 (C) 长期内存消耗最少,(B) 消耗两倍内存,(A) 内存消耗 4 倍。
当然,这将取决于数据的大小和形状。在这种情况下:
箱 | 模块导出 | 磁盘上的大小 (b) | 30 秒后添加到“heapUsed”的字节数 |
---|---|---|---|
C | 使用 JSON.parse() 的函数 | 1,400,667 | 1,934,336 |
B | 返回文本的函数 | 1,379,845 | 4,422,656 |
一个 | 常量 | 1,379,828 | 9,018,368 |
每个模块都单独测试,首先捕获 的输出,然后动态加载数据模块,访问数据,然后等待 10 秒和 30 秒加载后重新测量内存使用情况(不允许导入的资源超出范围)。在此电子表格中可以看到 3 次运行的结果(这些值是从基线调用到 的增量,以 kB 为单位)。memoryUsage()
memoryUsage()
我怀疑正在发生的事情是,源代码中的单个大型 JSON 字符串可以存储在连续的 RAM 中,而其他两种表示形式需要更多的单个对象和昂贵的“边缘”,因为缺乏更好的术语。令人惊讶的是,构造的变量占用的内存是函数的编译表示的两倍,该函数将对象作为文字返回!
但也许这并不奇怪:我假设文字的 AST 不能被 GC 编辑,无论它是常量还是函数,所以当模块在范围内时,你总是在任何可变存储之上支付内存成本。在所有条件相同的情况下,尽量在堆上存储尽可能少的存储时间。
评论
node --expose-gc
gc();
评论
JSON.parse()