做者:Lin Clark
譯者:xlaoyu
英文原文:Memory in WebAssembly (and why it’s safer than you think)git
轉載請註明出處,保留原文連接以及做者信息github
這是 WebAssembly 使用系列介紹的第二篇文章:web
Memory(內存,內存都以內存稱呼)在 WebAssembly 中的使用和在 JavaScript 中稍有不一樣。在 WebAssembly 裏,咱們能夠直接訪問原始字節,這可能會讓一些人感到擔心,但它實際上比你想象的更安全。數組
當一個WebAssembly模塊被實例化時,它須要一個內存對象。咱們能夠建立一個新 WebAssembly.Memory
對象並將其傳入。或者若是咱們沒傳,那麼引擎將建立一個內存對象並自動將其附加到該實例上。瀏覽器
全部 JS 引擎都會在內部建立一個ArrayBuffer。ArrayBuffer 是 JS 引用的 JavaScript 對象,JS 替咱們爲它分配內存。咱們告訴它須要多少內存,它會建立咱們須要大小的 ArrayBuffer 對象。安全
數組的索引能夠看做是內存地址。若是之後咱們須要更多的內存空間,能夠執行一種叫作 增加 的操做來擴大數組。函數
使用 JavaScript 的對象 ArrayBuffer
來操控 WebAssembly 的內存,達成了兩個目的:編碼
由於 ArrayBuffer 也只是一個 JavaScript 對象,這意味着 JavaScript 有足夠的能力能夠去操做內存裏的字節。基於這種方式,WebAssembly 和 JavaScript 能夠共享內存並來回傳遞值。code
它們使用數組下標去定位內存塊,而不是使用內存地址。cdn
例如,WebAssembly 能夠把一個字符串放進內存裏。首先把字符串編碼爲字節。。
而後把字節放進數組中。
而後它會將第一個索引(整數)返回給 JavaScript,因此 JavaScript 能夠將字節取出來並使用它們。
目前爲止,大多數 JavaScript 引擎都沒法直接使用字節來工做,因此咱們須要在 JS 這邊使用某些方法把字節轉化爲有用的數據類型,好比字符串。
在某些瀏覽器中,咱們可使用 TextDecoder 和 TextEncoder API。或者咱們能夠像 Emscripten 那樣在代碼中加入輔助函數,幫助咱們完成這件事情。
以上是使用 JS 對象操做 WebAssembly 內存的第一個優勢:能夠直接經過內存互相傳遞數據。
使用 JavaScript 對象處理 WebAssembly 內存的另一個好處就是:安全性。經過幫助防止瀏覽器級內存泄漏並提供內存隔離,它使事情更安全。
當咱們本身手動管理內存時,隨時可能忘記清除它。這可能會致使系統內存不足最終內存溢出。
咱們想象一下,若是一個 WebAssembly 模塊實例能夠直接訪問內存,而且在該實例執行完成退出上下文時忘記釋放該內存,那麼將會致使內存泄露。可是如今因爲內存對象是一個 JavaScript 對象,它的存在將由垃圾回收器追蹤着(儘管並無控制內容)。這意味着當 WebAssembly 模塊實例離開執行上下文時,整個內存數組將會被回收掉。
當人們得知 WebAssembly 模塊能夠直接訪問內存時,這可能會讓咱們有點緊張。咱們可能會覺得 WebAssembly 模塊能夠定位和訪問到它們本該不能訪問的內存,但事實並不是如此。
ArrayBuffer 對象邊界會提供一個限制,這是 WebAssembly 模塊能直接接觸到的內存邊界。
WebAssembly 能夠直接獲取該數組內部的字節,但它不能看到超出此數組邊界的任何內容。
例如,內存中的任何其餘JS對象(如全局window)都不能被 WebAssembly 訪問。這對安全性很是重要。
不管什麼時候在 WebAssembly 中進行讀取或寫操做時,引擎都會執行數組邊界檢查以確保地址位於 WebAssembly 實例的內存中。
若是代碼嘗試訪問超出界限的地址,則引擎將引起異常,這保護了其他的內存。
下篇文章,咱們一塊兒來看看什麼是 WebAssembly 的 table
對象。