JavaScript:阿特金筛法实施中的巨大结果数组内存不足

JavaScript: Out of Memory for huge result array in Sieve of Atkin implementation

目前我运行正在 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 实现的内存使用吗?

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

我正在使用:

提前致谢!

而不是 Array, which naïvely stores each of your flags as a double (and probably has even more memory overhead for its ability to store arbitrary mixed types), you might use a Uint8Array 或其他无符号整数格式,这将至少减少 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 之间的任何选择都将使用相同数量的内存。