分配 65536 个元素的数组后,AssemblyScript / WebAssembly 分配失败

Posted

技术标签:

【中文标题】分配 65536 个元素的数组后,AssemblyScript / WebAssembly 分配失败【英文标题】:AssemblyScript / WebAssembly fails allocation after 65536-element array allocated 【发布时间】:2021-10-22 09:07:00 【问题描述】:

我在分配内存时遇到问题,并且在网上找不到任何关于此案例的参考资料。特别是,如果我分配一个包含 65536 个元素(不是字节)或更多元素的数组,任何后续分配(即使是很小的一个)都会“失败”——当它成功执行时,它会返回一个与最近分配的数组重叠的指针。

我正在使用数组。我不确定在这里使用 StaticArray、Array 或 Float32Array 是否会改变行为,但我已经尝试了所有这些,但似乎没有任何改进。

AssemblyScript:

export function empty(): t 
  return new Array<f32>(16)


export function makeArray(count: u32): arr 
  let arr = new Array<f32>(count * 16)
  let j: u32

  for (let i: u32 = 0; i < count; i++) 
    for (j = 0; j < 16; j++) 
      //logU32(i * 16 + j)
      arr[i * 16 + j] = j as f32 + 1;
    
  

  return arr

宿主 JS:

console.log("memory.buffer.byteLength",LinAlg.memory.buffer.byteLength)
matrixBuffer = LinAlg.Matrix4.makeArray(6000)
console.log("matrixBuffer pointer", matrixBuffer)
console.log("empty pointer", LinAlg.Matrix4.empty())

我的脚本中的一些相关日志记录:

memory.buffer.byteLength(JS登录):655360 请求分配一个包含多少元素的数组(在 WASM 中登录):96,000 初始化每个缓冲区后的 Array.length(登录 WASM):96,000 返回给JS的指针值:21216 随后分配的 16 元素数组的指针值:21,216

如果我不分配第二个数组,则原始数组可以通过 __getArrayView() 在 JS 中用作 96,000 个元素的数组。就好像分配大数组有效,但会破坏内存分配器以进行任何后续操作。

理论上,我应该在堆中达到 byte (21,216 + 4 * 96,000) = 405,216,并且还剩下大约 250k 的内存。

提前感谢您提供的任何帮助!

【问题讨论】:

【参考方案1】:

来自 AssemblyScript Discord 上的 dcode:

听起来初始数组被 GC 过早收集(另一个分配可能会触发 GC 步骤),可能是因为该数组既没有从 Wasm 内部引用,也没有在外部 __pined?

我可以确认将分配行更改为:

matrixBuffer = LinAlg.__pin(LinAlg.Matrix4.makeArray(6000))

解决了这个问题。

【讨论】:

以上是关于分配 65536 个元素的数组后,AssemblyScript / WebAssembly 分配失败的主要内容,如果未能解决你的问题,请参考以下文章

如何增加数组长度和删去数组中的某个元素?

Assembly language 再读---续

c中可以定义变长数组吗

ASSEMBLY中的59代表什么? [重复]

数组有多少元素不为空?

net core中怎么获取类的assembly