WebAssembly中的内存工作原理与JavaScript中的内存略有不同。使用WebAssembly,您可以直接访问原始字节……这使某些人感到担忧。但这实际上比您想象的要安全。
什么是内存对象?
实例化WebAssembly模块时,它需要一个内存对象。您可以创建一个新的WebAssembly.Memory
并将该对象传递进来。否则,将自动创建一个内存对象并将其附加到实例。
JS引擎在内部所做的全部工作就是创建一个ArrayBuffer。 ArrayBuffer是JS引用的JavaScript对象。 JS为您分配内存。你告诉它需要多少内存,它将创建该大小的ArrayBuffer。
可以将数组的索引视为内存地址。而且,如果以后需要更多的内存,则可以执行“_growing_”操作,以使数组更大。
将WebAssembly的内存作为ArrayBuffer(作为JavaScript中的对象)处理有两件事:
- 使在JS和WebAssembly之间传递值变得容易
- 有助于使内存管理安全
JS和WebAssembly之间传递值
因为这只是一个JavaScript对象,所以这意味着JavaScript也可以在该内存的字节中挖掘数据。因此,以这种方式,WebAssembly和JavaScript可以共享内存并来回传递值。
他们不使用内存地址,而是使用数组索引访问每个box。
例如,WebAssembly可以在内存中放置一个字符串。它将编码为字节…
…然后将这些字节放入数组中。
然后它将第一个索引(整数)返回给JavaScript。因此,JavaScript可以提取字节并使用它们。
现在,大多数JavaScript都不知道如何直接使用字节。因此,您需要在JavaScript方面(例如在WebAssembly方面)进行某些操作,这些操作可以将字节转换为更有用的值(例如字符串)。
在某些浏览器中,可以使用 TextDecoder 和 TextEncoder API。或者,您可以将辅助函数添加到您的.js文件中。例如,类似 Emscripten 的工具可以添加编码和解码帮助器。
这就是WebAssembly内存只是JS对象的第一个好处。 WebAssembly和JavaScript可以直接通过内存来回传递值。
让内存访问更加安全
WebAssembly内存只是JavaScript对象,这还有另一个好处:安全性。通过帮助防止浏览器级内存泄漏并提供内存隔离,它使事情变得更安全。
内存泄漏
正如我在有关内存管理的文章中提到的那样,当您管理自己的内存时,您可能会忘记清除它。这可能会导致系统内存不足。
如果WebAssembly模块实例可以直接访问内存,并且如果忘记在超出范围之前清除该内存,则浏览器可能会泄漏内存。
但是因为内存对象只是一个JavaScript对象,所以垃圾回收器会跟踪它本身(即使它的内容不是)。
这意味着,当附加了内存对象的WebAssembly实例超出范围时,可以对整个内存数组进行垃圾回收。
内存隔离
当人们听到WebAssembly使您可以直接访问内存时,这会使他们有些紧张。他们认为,恶意的WebAssembly模块可能会进入并且无法在内存中进行挖掘。但事实并非如此。
ArrayBuffer的边界提供了一个边界。 WebAssembly模块可以直接接触的内存数量受到限制。
它可以直接触摸此数组内部的字节,但看不到该数组范围之外的任何内容。
例如,WebAssembly无法访问内存中的任何其他JS对象(例如全局窗口)。这对于安全性而言非常重要。
每当WebAssembly中有负载或存储时,引擎都会进行数组边界检查,以确保地址位于WebAssembly实例的内存中。
如果代码尝试访问越界地址,则引擎将引发异常。这样可以保护其余的内存。
PS: 本文属于翻译,原文
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。