ArrayBuffers和SharedArrayBuffers的介紹
在《內存管理技術的具體實現介紹》一文中,我解釋了像JavaScript這樣的內存管理語言是如何工作的,我還解釋了手動內存管理如何在C語言中工作。
本文就讓我談論ArrayBuffers和SharedArrayBuffers。這是因為即使你正在使用具有自動內存管理的JavaScript,ArrayBuffers也可以為你提供一種方法來手動處理一些數據。
正如大家在上一篇文章中了解的那樣,出於對自動內存管理安全性的考慮,開發人員更容易使用它,但也會增加一些開銷。但在某些情況下,這種自動內存管理可能會導致性能問題。
例如,當你在JS中創建變數時,引擎必須判斷這是什麼樣的變數,以及如何在內存中進行表示。因為引擎是處於判斷的狀態,所以JS引擎通常會需要的空間比實際的處理變數的空間更多一些。根據變數的不同,內存插槽可能比需要大2-8倍,這可能會導致大量內存的浪費。
另外,創建和使用JS對象的某些模式可能會使得收集垃圾變得困難。如果你正在進行手動內存管理,則可以選擇適用於你正在使用的分配比例甚至可以取消磨人的分配策略。
不過大多數時候,由於手動內存管理比較麻煩,很多人會選擇自動內存管理。另外,大多數用戶對性能不敏感,所以總體來說,手動內存管理的使用不太多。對於常見的一些情況,手動內存管理甚至可能會讓性能更慢。
但是對於那些需要在低級別狀態下運行並希望代碼儘可能快的用戶來說,ArrayBuffers和SharedArrayBuffers則是一個比較好的選擇。
ArrayBuffer的工作原理
它基本上就像使用任何其他JavaScript數組一樣,除了使用ArrayBuffer之外,你不能將任何JavaScript類型放入其中,例如對象或字元串。唯一可以放入的是位元組,可以使用數字表示。
有一點我應該在這裡明確指出,你並需要將這個位元組直接添加到ArrayBuffer中。因為ArrayBuffer本身並不知道位元組應該有多大,或者不同的數字應該如何轉換成位元組。
ArrayBuffer本身就是一行一堆0和1組成的序列, ArrayBuffer不知道這個數組中第一個元素和第二個元素之間如何分割。
為了提供上下文,實際上會將其分解成各個小框,我們需要將它包裝在所謂的視圖中。這些數據視圖可以添加類型化的數組,並且可以使用許多不同類型的類型數組。
例如,你可以使用Int8類型的數組,將其分解為8位位元組。
或者你可以有一個無符號的Int16數組,它可以將其分解成16位,處理它就好像是處理一個無符號的整數。
你甚至可以在同一個基本緩衝區上擁有多個視圖。不同的視圖將給你呈現相同的操作下的不同結果。
例如,如果我們從這個ArrayBuffer的Int8視圖獲取元素0和1,那麼它將給出與Uint16視圖中的元素0不同的值,即使它們包含完全相同的位。
這樣,ArrayBuffer基本上就類似於原始內存,你會用C語言模擬一種直接的內存訪問,
你可能會想知道為什麼我們不讓程序員直接訪問內存,而是添加這一層抽象化的內存。直接訪問內存將會打開一些安全漏洞。。
SharedArrayBuffer的工作原理
在介紹SharedArrayBuffers之前,我需要解釋一下並行運行代碼和JavaScript。
使用並行運行代碼,可以讓你的代碼運行速度更快,或者使其對用戶事件的響應更快。要做到這一點,你需要分別獨立運行。
在一個典型的應用程序中,所有的工作都由主線程來處理。我之前已經談過了這個,主線程就像一個全棧開發者。它負責JavaScript,DOM和布局。
所以刪除主線程的工作負載會對運行速度有很大的幫助。在某些情況下,ArrayBuffers可以減少主線程所需的工作量。
但有時減少主線程的工作量是不夠的,有時你需要對要運行的工作分解,逐個擊破。
在大多數編程語言中,通常分割工作的方式是使用一種叫做線程的東西,就像有多個人在一個項目上工作。如果你有相互獨立的任務,你可以給他們不同的線程。然後,這兩個線程可以同時處理單獨的任務。
在JavaScript中,你的方式是使用名為web worker的東西。這些web worker與你在其他語言中使用的線程略有不同。默認情況下,它們不共享內存。
這意味著如果要與其他線程共享一些數據,則必須將其複製。這是通過postMessage函數完成的。
postMessage會把你放入的任何對象序列化,然後發送到另一個web worker,反序列化並放入內存中,這是一個相當緩慢的過程。
對於某些類型的數據,像ArrayBuffers,你可以做所謂的傳輸內存。這意味著對特定的內存塊進行移動,以便其他web worker可以訪問它。
但是,第一個web worker不再可以訪問它了。
這個方法僅適用於一些特殊情況,想要具有高性能的並行性,真正需要的是具有共享內存,這就要用到SharedArrayBuffers。
使用SharedArrayBuffer,這兩個線程都可以從同一塊內存中寫入數據和讀取數據。
這意味著它們不需要使用PostMessage的通信開銷和延遲,web worker就可以立即訪問數據。
儘管這兩個線程的同時立即訪問有一些危險,但這樣卻可以引起所謂的競爭條件即兩個或多個進程讀寫某些共享數據,而最後的結果取決於進程運行的精確時序。
SharedArrayBuffers的當前用途
SharedArrayBuffers即將在所有主流瀏覽器中被用到。
目前它們已經在Safari中開始運行(在Safari 10.1中)。 Firefox和Chrome都將在今年的7月和8月發行它們,而Edge計劃在今年秋天的Windows更新中用到。
即使在所有主流瀏覽器都可用,我們也不希望應用程序開發人員直接使用它們。其實我的建議是應該使用最高級別的抽象。
我期望的是,JavaScript庫開發人員將創建庫,使你可以更輕鬆,更安全地使用SharedArrayBuffers。
此外,一旦SharedArrayBuffers內置到平台中,WebAssembly可以使用它們來實現對線程的支持。一旦該功能實現,你將能夠使用一種語言的並發抽象,如Rust語言, 其神奇的並發模型,能將安全和並發完美地統一在一起。
在下一篇文章中,我將介紹這些庫的開發者如何在避免競爭的條件下同時建立這些抽象的工具(Atomics)。
![](https://pic.pimg.tw/zzuyanan/1488615166-1259157397.png)
![](https://pic.pimg.tw/zzuyanan/1482887990-2595557020.jpg)
※通過Edge瀏覽器遠程代碼執行PoC發布
※iOS應用與Golduck惡意軟體C2伺服器通信
TAG:嘶吼RoarTalk |