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方面)进行某些操作,这些操作可以将字节转换为更有用的值(例如字符串)。

在某些浏览器中,可以使用 TextDecoderTextEncoder API。或者,您可以将辅助函数添加到您的.js文件中。例如,类似 Emscripten 的工具可以添加编码和解码帮助器。

这就是WebAssembly内存只是JS对象的第一个好处。 WebAssembly和JavaScript可以直接通过内存来回传递值。

让内存访问更加安全

WebAssembly内存只是JavaScript对象,这还有另一个好处:安全性。通过帮助防止浏览器级内存泄漏并提供内存隔离,它使事情变得更安全。

内存泄漏

正如我在有关内存管理的文章中提到的那样,当您管理自己的内存时,您可能会忘记清除它。这可能会导致系统内存不足。
如果WebAssembly模块实例可以直接访问内存,并且如果忘记在超出范围之前清除该内存,则浏览器可能会泄漏内存。
但是因为内存对象只是一个JavaScript对象,所以垃圾回收器会跟踪它本身(即使它的内容不是)。
这意味着,当附加了内存对象的WebAssembly实例超出范围时,可以对整个内存数组进行垃圾回收。

内存隔离

当人们听到WebAssembly使您可以直接访问内存时,这会使他们有些紧张。他们认为,恶意的WebAssembly模块可能会进入并且无法在内存中进行挖掘。但事实并非如此。
ArrayBuffer的边界提供了一个边界。 WebAssembly模块可以直接接触的内存数量受到限制。

它可以直接触摸此数组内部的字节,但看不到该数组范围之外的任何内容。
例如,WebAssembly无法访问内存中的任何其他JS对象(例如全局窗口)。这对于安全性而言非常重要。
每当WebAssembly中有负载或存储时,引擎都会进行数组边界检查,以确保地址位于WebAssembly实例的内存中。
如果代码尝试访问越界地址,则引擎将引发异常。这样可以保护其余的内存。

PS: 本文属于翻译,原文


iyacontrol
1.4k 声望2.7k 粉丝

专注kubernetes,devops,aiops,service mesh。


引用和评论

0 条评论