为什么在 WebAssembly 中 ALLOW_MEMORY_GROWTH=1 失败而 TOTAL_MEMORY=512MB 成功?

Bra*_*tty 7 emscripten webassembly

我有一个图像处理 Wasm 项目,它将不同的二值化算法应用于给定的图像。当我运行其中一种算法时,会产生此错误:

Uncaught abort("Cannot enlarge memory arrays to size 17100800 bytes (OOM). Either
(1) compile with  -s TOTAL_MEMORY=X  with X higher than the current value 16777216,
(2) compile with  -s ALLOW_MEMORY_GROWTH=1  which allows increasing the size at runtime, or
(3) if you want malloc to return NULL (0)
instead of this abort, compile with  -s ABORTING_MALLOC=0 ") at Error
Run Code Online (Sandbox Code Playgroud)

编译后"-s ALLOW_MEMORY_GROWTH=1",该算法在Chrome中并没有出错,而是将图像变成了黑色。连续第二次运行出现此错误:

Uncaught RuntimeError: memory access out of bounds

第一次在 Edge 中运行时,42.17134.1.0我收到此错误:

SCRIPT5147: The ArrayBuffer is detached.

有趣的是,删除该选项并将其替换为"-s TOTAL_MEMORY=512MB"修复了问题。

所以我的问题是:难道不ALLOW_MEMORY_GROWTH=1应该在运行时自动为我扩展堆内存并且几乎可以替代 TOTAL_MEMORY 吗?我讨厌在编译时锁定我的应用程序可以使用的最大内存的想法。使用 Chrome 73.0.3683.103/74.0.3729.108 (Official Build) (64-bit)和 Firefox进行测试66.0.3 (64-bit)

编辑 我能够使用以下代码隔离问题。

编译用于调试:

em++ -O0 -o ./dist/doxaWasm.js doxaWasm.cpp -std=c++1z -s WASM=1 -s NO_EXIT_RUNTIME=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['writeAsciiToMemory']" -g4 --source-map-base http://localhost:8080/ -s ALLOW_MEMORY_GROWTH=1
Run Code Online (Sandbox Code Playgroud)

C++ 代码片段:

extern "C"
{
    void EMSCRIPTEN_KEEPALIVE Initialize(uint8_t* data, const int width, const int height)
    {
        // Large enough to force a reallocation.
        // If there is no reallocation, everything works.
        std::vector<int64_t> integral_image1(width*height*10);

        data[0] = 123;
    }
}
Run Code Online (Sandbox Code Playgroud)

JavaScript 代码片段:

...
var size = width * height;
var heapPtr = Module._malloc(size);
var data = new Uint8ClampedArray(Module.HEAPU8.buffer, heapPtr, size);
... // Populate 'data' with 8bit grayscale based on canvas ImageData
Module._Initialize(data.byteOffset, width, height);
console.log(data[0]); // Equals 123 if there is no reallocation
Run Code Online (Sandbox Code Playgroud)

Bra*_*tty 6

我知道发生了什么事。这是由于我自己的 na\xc3\xafvet\xc3\xa9 主题。\n我创建的 Uint8ClampedArray 充当底层内存的窗口,将其塑造成我可以访问的形式。但在重新分配时,HEAPU8 缓冲区正在发生变化,导致它与我的数组“分离”。

\n\n

然后,可以在 Wasm 方法调用之前创建一个映射数组以将数据传递给函数,或者在 Wasm 调用之后创建一个映射数组以从函数读取数据。在上面的示例中,我需要其中两个,一个在前面,一个在后面,因为之前创建的数组可能会分离。

\n\n
...\nvar size = width * height;\nvar heapPtr = Module._malloc(size);\nvar input = new Uint8ClampedArray(Module.HEAPU8.buffer, heapPtr, size);\n... // Populate \'data\' with 8bit grayscale based on canvas ImageData\nModule._Initialize(heapPtr, width, height);\nvar output = new Uint8ClampedArray(Module.HEAPU8.buffer, heapPtr, size);\nconsole.log(output[0]);\n
Run Code Online (Sandbox Code Playgroud)\n\n

我讨厌回答自己的问题......但希望这可以让遇到这种情况的人省去一些头痛。任何在该主题上具有更多专业知识的人都可以澄清该答案中可能需要的任何部分。

\n

  • 帮助过我。请随意提出并回答您自己的问题 - 就像您自己的个人开发博客一样......所以说它很好。 (2认同)