【问题标题】:Why does Math.random() (in Chrome) allocate memory that needs cleanup by the Garbage Collector (gc)?为什么 Math.random()(在 Chrome 中)分配需要垃圾收集器 (gc) 清理的内存?
【发布时间】:2021-12-18 02:27:09
【问题描述】:

故事

在对性能关键代码进行一些测试期间,我观察到了 Math.random() 的副作用,我不明白。我在找

  • 一些深入的技术解释
  • 伪造我的测试(或期望)
  • 链接到 V8 问题/错误票证

问题

看起来调用Math.random() 分配了一些需要由 Gargabe 收集器 (gc) 清理的内存。

测试:使用 Math.random()

    const numberOfWrites = 100;
    const obj = {
        value: 0
    };

    let i = 0;

    function test() {
        for(i = 0; i < numberOfWrites; i++) {
            obj.value = Math.random();
        }
    }

    window.addEventListener('DOMContentLoaded', () => {
        setInterval(() => {
             test();
        }, 10);
    });

观察 1:Chrome 配置文件

Chrome:95.0.463869,Windows 10,Edge:95.0.1020.40

在浏览器中运行此代码并记录性能配置文件将导致经典的记忆之字形

Memory profile of Math.random() test

观察 2:火狐

Firefox 开发者:95,Windows 10

未检测到垃圾收集 (CC/GCMinor) - 内存相当线性

解决方法

crypto.getRandomValues()

使用 self.crypto.getRandomValues` 将 Math.random() 替换为足够大的预先计算的随机数数组。

【问题讨论】:

    标签: javascript performance random garbage-collection v8


    【解决方案1】:

    (这里是 V8 开发人员。)

    是的,这是意料之中的。这是一个(非常基本的)设计决策,不是错误,并且与Math.random() 没有严格关系。 V8 将浮点数“装箱”为堆上的对象。那是因为它在对象中每个字段使用 32 位,这对于 64 位双精度显然是不够的,而间接层解决了这个问题。

    有一些特殊情况可以避免这种装箱:

    • 在优化代码中,用于永远不会离开当前函数的值。
    • 适用于其值为足够小的整数(“Smis”,带符号的 31 位整数范围)的数字。
    • 用于仅将数字视为元素的数组中的元素(例如 [1, 2.5, NaN],但不是 [1, true, "hello"])。
    • 可能还有其他我现在没有想到的情况。此外,所有这些内部细节都可能(并且确实!)随着时间而改变。

    Firefox 使用一种完全不同的技术来存储内部引用。好处是它避免了将数字装箱,缺点是它使用更多的内存来存储不是数字的东西。两种方法都不比另一种更好,只是一种不同的权衡。

    一般来说,您不必担心这一点,这只是您的 JavaScript 引擎在做它的事情 :-)

    问题:在浏览器中运行此代码并记录性能配置文件将导致经典的内存之字形

    为什么会有这样的问题?这就是垃圾回收内存的工作原理。 (另外,为了正确看待事情:GC 在您的配置文件中每 ~8s 只花费 ~0.3ms。)

    解决方法:使用 self.crypto.getRandomValues` 将 Math.random() 替换为足够大的预先计算的随机数数组。

    用大而长寿命的数组替换微小的短寿命 HeapNumbers 听起来不是节省内存的好方法。

    如果它真的很重要,避免数字装箱的一种方法是将它们存储在数组中,而不是作为对象属性。但是在你的代码中经历难以维护的扭曲之前,一定要衡量它对你的应用程序是否真的很重要。在微基准测试中很容易展示巨大的影响,但很少看到它在实际应用中产生如此大的影响。

    【讨论】:

    • 现在一切都说得通了 ;-) 我正在做一个技术实验,需要尽可能快,避免尽可能多的 gc,内存不是那个问题。在数组中使用数字来避免框可能非常有趣。
    猜你喜欢
    • 1970-01-01
    • 2012-11-26
    • 1970-01-01
    • 2015-04-10
    • 2012-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多