AssemblyScript与JavaScript共享内存时数组修改不生效及段错误问题的解决方案咨询
AssemblyScript与JavaScript共享内存时数组修改不生效及段错误问题的解决方案咨询
我来帮你梳理下这两个问题的原因和解决办法,都是AssemblyScript(AS)和JavaScript共享内存时的常见坑:
问题1:直接传递TypedArray修改不生效
当你在JS里把Float64Array直接传给AS函数时,AS默认会把这个数组拷贝到自己的内存空间里操作,而不是直接修改JS端的原始数组内存。所以你在AS里写out[0] = 1,修改的只是AS内存里的拷贝,JS端的原数组自然不会有变化。
解决办法:传递共享内存的字节偏移量
要让AS直接操作JS端的共享内存,你需要传递数组在共享内存中的字节偏移量,而不是直接传TypedArray对象:
修改后的AssemblyScript代码
// 接收共享内存中的字节偏移量,直接操作对应位置的Float64Array export function b(offset: usize): void { const arr = changetype<Float64Array>(offset); arr[0] = 1.0; }
修改后的JavaScript代码
import { b, memory } from './release.js'; // 创建基于AS共享内存的Float64Array视图 const out = new Float64Array(memory.buffer, 0, 1); // 传递数组的字节偏移量给AS函数 b(out.byteOffset); console.assert(out[0] === 1); // 现在断言会成功
不过要注意:如果AS的内存因为扩容(比如创建大量对象)被替换,之前创建的TypedArray会失效。更稳妥的方式是让AS来分配内存,JS端再获取对应视图:
更可靠的共享内存实现
AssemblyScript代码
// 分配Float64Array并返回其在共享内存中的字节偏移量 export function createFloat64Arr(length: i32): usize { const arr = new Float64Array(length); return changetype<usize>(arr); } // 通过偏移量修改数组指定位置的值 export function setFloat64(offset: usize, index: i32, value: f64): void { const arr = changetype<Float64Array>(offset); arr[index] = value; }
JavaScript代码
import { createFloat64Arr, setFloat64, memory } from './release.js'; // 让AS分配内存,获取偏移量 const arrOffset = createFloat64Arr(1); // 创建JS端的视图,指向AS分配的内存区域 const out = new Float64Array(memory.buffer, arrOffset, 1); // 修改数组值 setFloat64(arrOffset, 0, 1.0); console.assert(out[0] === 1); // 断言成功
问题2:使用changetype出现段错误
你之前的代码触发段错误,核心原因是AS的垃圾回收(GC)回收了你创建的数组内存:当你在AS里用new Float64Array创建数组后,如果AS的GC认为这个数组没有被引用,就会释放这块内存,此时JS端的视图再去访问就会触发段错误。
解决办法:固定内存防止GC回收
你可以用AS提供的__pin函数手动固定数组,或者用全局变量持有数组引用,避免被GC回收:
修改后的AssemblyScript代码
// 导入内存固定/释放函数 import { __pin, __unpin } from 'assemblyscript'; // 全局变量持有数组引用,防止GC回收 let pinnedArr: Float64Array | null = null; export function new_f64_arr(n: i32): usize { const out = new Float64Array(n); __pin(out); // 固定数组,阻止GC回收 pinnedArr = out; // 额外用全局变量持有引用,双重保障 return changetype<usize>(out); } export function b(ptr: usize): void { const arr = changetype<Float64Array>(ptr); arr[0] = 1; } // 可选:用完后释放内存 export function releaseArr(): void { if (pinnedArr) { __unpin(pinnedArr); pinnedArr = null; } }
修改后的JavaScript代码
import { new_f64_arr, b, releaseArr, memory } from './release.js'; const arrOffset = new_f64_arr(2); const arr = new Float64Array(memory.buffer, arrOffset, 2); arr[0] = 77; b(arrOffset); console.log(arr[0]); // 输出1,不会触发段错误 // 用完后记得释放内存,避免内存泄漏 releaseArr();
备注:内容来源于stack exchange,提问作者januw a
相关产品推荐
相关产品推荐

