这是系列文章第二篇:
WebAssembly中的内存与JavaScript中的内存有所不同。运用WebAssembly,您能够直接接见原始字节码…这能够令人担忧。然则,它确实比你设想中的要平安。
什么是 memory 对象?
当 WebAssembly 模块被实例化时,它须要一个 memory 对象。你能够建立一个新的WebAssembly.Memory并通报该对象。假如没有建立 memory 对象,在模块实例化的时刻将会自动建立,而且通报给实例。
JS引擎建立一个ArrayBuffer(我在另一篇文章中诠释)来做这件事变。ArrayBuffer 是 JS 援用的 JavaScript 对象。JS 为你分派内存。你通知它须要若干内存,它会建立一个对应大小的ArrayBuffer。
数组的索引能够视为内存地点。假如你须要增添它的内存,你能够运用 grow
要领让数组变大。
ArrayBuffer 做了两件事变,一件是做 WebAssembly 的内存,别的一件是做 JavaScript 的对象。
它使 JS 和 WebAssembly 之间通报内容更轻易。
使内存治理更平安。
JS 和 WebAssembly 之间传值
由于 ArrayBuffer 是一个 JavaScript 对象,这意味着 JavaScript 也能够获取到这个 memory 中的字节。所以经由过程这类体式格局, WebAssembly 和 JavaScript 能够同享内存,而且相互传值。
运用数组索引来接见每一个字节,而不是运用内存地点。
比方,WebAssembly 想将一个字符串写入内存。它须要将字符串转换成字节码。
然后把这些字节码放进数组。
然后将字符串地点的内存位置的第一个位置,也就是数组的某个索引,通报给 JavaScript。JavaScript 能够依据索引从 ArrayBuffer 中拿到字符串
如今,很多人并不知道如安在 JavaScript 中运用字节码。你须要将字节码转换为有效的内容,比方说字符串。
在一些浏览器中,你能够运用TextDecoder和TextEncoderAPI来处置惩罚。或许你能够在你的js文件里增加一些协助函数。比方,Emscripten就能够帮你增加编码和解码的要领。
所以,WebAssembly memory 最好的处所就是它是一个 JS 对象。WebAssembly 和 JavaScript 能够直接运用 memory 互相传值。
让 memory 存取更平安
别的一个优点是,WebAssembly memory 只是一个 JavaScript 对象:平安。经由过程防备浏览器级内存走漏并供应内存断绝,使事变变得更平安。
内存走漏
正如我在内存治理的文章中提到的,当你治理本身的内存时,你能够会遗忘消灭它。这能够致使体系内存不足。
假如 WebAssembly 模块实例直接接见内存,而且假如在超出局限之前遗忘消灭该内存,那末浏览器能够会走漏内存。
由于内存对象只是一个JavaScript对象,所以它本身就被渣滓接纳器跟踪(尽管它的内容不会渣滓接纳)。
也就是说,WebAssembly 实例被移除今后,一切的内存数组将会被接纳。
内存断绝
当人们听到WebAssembly让你直接接见内存时,他们能够有点慌张。他们以为,一个歹意的 WebAssembly 模块能够会进入并在内存中干坏事,这是相对不允许的。但现实并非如此。
ArrayBuffer 供应了边境。WebAssembly 模块能够直接治理的内存是受限定的。
它能够直接治理该数组内部的字节,但它看不到任何超出此数组局限的内容。
比方,内存中的任何别的 JS 对象,如 window 对象,WebAssembly无法接见。这对平安性非常重要。
每当 WebAssembly 中有操纵内存时,引擎会举行数组限定搜检,以确保该地点位于 WebAssembly 实例的内存中。
假如代码尝试接见超出局限的地点,引擎将抛出非常。这庇护了别的的内存。
所以这就是 memory 相干的内容。鄙人一篇文章中,我们将看研讨一些关于平安性的别的范例的 import 数据:table import。
About
Lin 是Mozilla Developer Relations团队的工程师。她运用 JavaScript、WebAssembly、Rust 和 Servo,也画一些漫画。