避免使用单个数字作为对象的key

背景

同事开发一个表格,一次性渲染5w+条数据。但在渲染某些数据时,内存暴增,经排查,发现其数据用了数字90作为对象的key。

分析

我们猜测,当用数字作为对象的key时,数据将以数组的形式进行存储。由于其中拥有大量的节点(空节点也要占据内存),导致内存飙升。

使用chrome浏览器无痕模式进行验证,在控制台输入如下测试代码,观察内存变化:

let a = {}
let indexValue = 200

for(var i = 0; i < 500; i++) {
    a[i] = {}
    for (var j = 0; j < 500; j++) {
        a[i][j] = {}
        a[i][j][indexValue] = {}
    }
}

通过不断改变indexValue的值,得到indexValue和内存占用的关系如下:

indexValue memory size(M)
9 50
90 171
200 336
500 786
600 936
1023 1572
1024 35
1028 35
9999 35

可以看到,随着indexValue的不断增加,内存也不断升高,直到indexValue值为1023时内存占用达到顶峰,随后立即断崖式下降。

v8 的官网文章fast-properties也有提及。

结论

当我们使用对象存储数据时,不要用数字作用对象的key,以避免内存浪费。

更进一步

如上所述,使用超过1023的数字作为对象key,好像也可以呢。现在我们使用大数字9999和字符串absdfsd作为对象key,分别测量它们的内存占用情况:

let a = {}

for(var i = 0; i < 10; i++) {
    a[i] = {9999: {}}
}

使用数字9999内存占用558 + 796 + 408 = 1762b:

let a = {}

for(var i = 0; i < 10; i++) {
    a[i] = {absdfsd: {}}
}

使用字符串absdfsd内存占用 632 + 468 + 76 + 20 = 1196b:

显然,字符串作为key更省内存。原因是,使用数字作为对象key,数据内部会额外保存一个数组,如下图。随着循环次数的增加,字符串省内存的优势会更加明显。

PS. 再来看看动态key,使用如下测试代码,内存占用情况又如何呢:

let a = {}

for(var i = 0; i < 5000; i++) {
    a[i] = {[9999 + i]: {}}
}
let a = {}

for(var i = 0; i < 5000; i++) {
    a[i] = {['abcd' + i]: {}}
}

这里就不截图了,有兴趣的同学可以自己尝试下。直接给结果:9999 + i => 798,232abcd + i => 890,132,可以看到,两者占用的内存差别较小,数字key反而更省内存。

引用

posted @ 2022-08-11 18:30  Liaofy  阅读(249)  评论(0编辑  收藏  举报