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: 本文属于翻译,原文