1. 程式人生 > >共享記憶體和Atomics 1、記憶體管理速成課程

共享記憶體和Atomics 1、記憶體管理速成課程

作者:Lin Clark

譯者:Cody Chan

-------------

這是圖解 SharedArrayBuffers 系列的第一篇:

  1. 記憶體管理速成課程
  2. 圖解 ArrayBuffers 和 SharedArrayBuffers
  3. 用 Atomics 避免 SharedArrayBuffers 競爭條件

為了更好地理解 JavaScript 裡的 ArrayBuffer 和 SharedArrayBuffer,首先應該瞭解點記憶體管理知識

你可以把一個機器的記憶體想成一個一個的盒子,我把它們當作辦公室的郵箱或者幼兒園裡放小孩東西的格子

如果你想把某個東西留給某個小孩,你就把東西放到格子裡

每個盒子旁邊都有一個編號,這就是記憶體地址,用於告訴別人如何去找到你留的東西

每個盒子大小都一樣,可以存放特定容量東西。盒子的具體容量取決於機器,這個大小我們稱為字長,一般為 32 位或者 64 位。不過,為了展示方便,我這裡字長用 8 位

如果你想把數字 2 放到盒子裡,這很容易做到,因為數字很容易用二進位制表示

但是如果你想放一個非數字型別的呢?比如字母 H?

我們需要一種方式可以用數字來表示它,這需要藉助編碼技術,類似 UTF-8 。首先,我們需要一個東西可以把字母轉為數字……類似一個編碼環,接下來就可以儲存了

當我們從盒子裡取回的時候,我們需要把取出的數字放到解碼環裡翻譯回字母 H

自動記憶體管理

如果你是寫 JavaScript 的,實際上你根本不需要關心記憶體,它對使用者是透明的,這意味著你無法直接操縱記憶體

與此相對的, JS 引擎扮演著中間人角色,它為你管理好記憶體

我們用 React 舉個例子,比如建立一個變數

JS 引擎通過一個編碼器得到這個變數的二進位制表示

然後,它會找到記憶體中可以放這個值的位置,這個過程稱為記憶體分配

緊接著,引擎會持續追蹤這個變數,看其是否還在程式中被使用。如果這個變數已經沒有引用了,這塊記憶體會被回收,JS 引擎就又可以在這裡放新的值了

追蹤記憶體中的變數(字串、物件以及其它型別)並且在沒有引用的時候清除它們的過程我們稱作垃圾回收

類似 JavaScript 這種程式碼無法直接處理記憶體的語言叫做自動記憶體管理(memory-managed)語言

記憶體自動管理確實讓開發者省了不少心,但是這也會帶來額外的開銷,這些額外開銷會讓程式的效能無法評估

手動記憶體管理

手動記憶體管理的語言不太一樣,繼續上面例子,看 React 用 C 寫的話(藉助 WebAssembly 是 可能的)會如何處理記憶體

不像 JavaScript,C 沒有單獨的記憶體管理抽象層,相反,你得直接與記憶體打交道。你可以從記憶體中直接拿東西,也可以直接往記憶體裡存東西

當你把 C 或者其它語言編譯為 WebAssembly 時,編譯工具會在 WebAssembly 裡增加一些輔助程式碼。比如,它會加入編解碼的程式碼,這些程式碼我們稱為執行時環境,執行時環境會幫助處理一些類似 JS 引擎幫 JS 做的事

但是,對於手動管理記憶體的語言,執行時不會包括垃圾回收

這並不意味著你需要完全由自己處理記憶體,即使在這類語言裡,執行時你依然會得到一些輔助。比如,C 語言執行時會在一個 free list 裡追蹤可以使用的記憶體地址

你可以使用 malloc 函式(記憶體分配的簡稱)向執行時發出可以滿足你資料儲存需要的記憶體請求,這些記憶體會被從 free list 拿下來。當你用完了,需要呼叫 free 去釋放記憶體,這些記憶體會被加回 free list

你必須清楚知道什麼時候去呼叫這些函式,這就是為什麼我們叫手動記憶體管理

作為一個開發者,知道什麼時候去釋放什麼地方的記憶體是一件困難的事。如果你在錯誤時機處理了,這很可能會導致 BUG,甚至安全漏洞;如果你不處理,就會導致記憶體洩露

這就是為什麼很多語言選擇自動記憶體管理去避免人為錯誤,但是這犧牲了效能,下篇文章