【问题标题】:JavaScript: Out of Memory for huge result array in Sieve of Atkin implementationJavaScript:阿特金筛子实现中巨大结果数组的内存不足
【发布时间】:2019-06-16 08:25:18
【问题描述】:

目前我正在 JavaScript、asm.js 和 WebAssembly 之间运行一些基准测试。为此,我实现了一个使用阿特金筛法搜索素数的小程序。

为了使上升可以忽略不计,我正在计算最高 500'000'000 的素数。我的问题是,JavaScript 实现内存不足,因为结果数组变得很大。

这是我目前的实现:

const AMOUNT = 500000000;

function getPrimes() {
  const limit = AMOUNT;
  const width = Math.sqrt(limit);
  let i, j, x, y, z;
  let primes = new Array(limit);

  const begin = performance.now();
  for (x = 1; x <= width; x++) {
    for (y = 1; y <= width; y++) {
      z = 4 * x * x + y * y;
      if (z < limit && (z % 60 == 1 || z % 60 == 13 || z % 60 == 17 || z
          % 60 == 29 || z % 60 == 37 || z % 60 == 41 || z % 60 == 49
          || z % 60 == 53)) {
        primes[z] = !primes[z];
      }

      z = 3 * x * x + y * y;
      if (z < limit && (z % 60 == 7 || z % 60 == 19 || z % 60 == 31 || z
          % 60 == 43)) {
        primes[z] = !primes[z];
      }

      z = 3 * x * x - y * y;
      if (x > y && z < limit && (z % 60 == 11 || z % 60 == 23 || z % 60
          == 47 || z % 60 == 59)) {
        primes[z] = !primes[z];
      }
    }
  }

  const end = performance.now();

  let last_prime = 0;
  for (i = limit; i >= 0; i--) {
    if(primes[i] == 1) {
      last_prime = i;
      break;
    }
  }

  primes = null;
  time_spent = end - begin;
  console.log(time_spent/1000 + ', ' + last_prime);
}

document.addEventListener("DOMContentLoaded", function() {
  let i;
  for (i = 0; i <= 10; i++) {
    getPrimes();
  }
});

这是我运行它的 HTML:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Find Primes</title>
    <script src="./find-primes.js"></script>
  </head>
  <body>
    Check the console.
  </body>
</html>

到目前为止我已经尝试过: - 确保primes 数组在每次运行后通过将其无效来收集。 - 分配整个数组一次。

你有更多的想法来优化我的 JavaScript 实现的内存使用吗?

我试图阻止的是拆分数组或在不同的迭代中计算结果,因为我想对原始计算性能进行基准测试。内存管理应该不会对测试产生任何影响。

我正在使用:

  • Google Chrome:版本 75.0.3770.90(官方构建)(64 位)
  • Mozilla Firefox:版本 67.0.2(64 位)

提前谢谢你!

【问题讨论】:

    标签: javascript performance performance-testing benchmarking primes


    【解决方案1】:

    您可以使用Uint8Array 或其他未签名的Uint8Array,而不是Array,后者将您的每个标志天真地存储为double(并且可能由于其存储任意混合类型的能力而具有更多的内存开销)整数格式,可以将内存使用量减少至少 64 倍。

    您需要修改初始化、切换和检查标志的方式。

    初始化:

    const BitArray = Uint8Array; // or Uint16Array, Uint32Array
    const BITS_PER_ELEMENT = BitArray.BYTES_PER_ELEMENT * 8;
    const BIT_SHIFT = Math.log2(BITS_PER_ELEMENT);
    const BIT_MASK = BITS_PER_ELEMENT - 1;
    let primes = new BitArray(Math.ceil(limit / BITS_PER_ELEMENT));
    

    切换:

    primes[z >> BIT_SHIFT] ^= 1 << (z & BIT_MASK);
    

    检查:

    if (primes[i >> BIT_SHIFT] & (1 << (i & BIT_MASK)))
    

    Uint8ArrayUint16ArrayUint32Array 之间的任何选择都将使用相同数量的内存。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-04
      • 2015-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-15
      相关资源
      最近更新 更多