1. 程式人生 > 實用技巧 >老司機帶你秒懂記憶體管理 - 第一部(共三部)

老司機帶你秒懂記憶體管理 - 第一部(共三部)

要理解為什麼將 ArrayBuffer 和 SharedArrayBuffer 新增到 JavaScript 中,你需要了解一些關於記憶體管理的內容。

你可以將機器中的記憶體看作一堆盒子。就像你在辦公室裡的郵箱,或是小孩子們使用的收納箱。

如果你想要為其他孩子留下一些東西,你可以把它放在一個盒子裡。

在每個盒子旁邊都有一個數字,這些數字就是記憶體地址,用來告訴別人在哪裡找到你留給他們的東西。

這些盒子中的每一個都具有相同的尺寸,並且可以容納一定量的資訊。盒子的尺寸取決於機器。這個大小稱為字長。它通常是32位或64位。但是為了顯示方便,這裡我們使用8位字長。

如果我們想把數字2放在其中一個盒子中,我們可以很容易地做到這一點。數字很容易轉換成二進位制

如果我們想要的東西不是數字怎麼辦?比如字母 H?

我們需要一個類似UTF-8的編碼來用數字代替這些東西。而為了把這些東西轉換成數字,我們需要一個類似編碼器環的工具。之後我們就可以儲存它了。

當我們想把它從盒子裡拿出來的時候,必須通過解碼器把它轉換回 H。

自動記憶體管理

當你在使用 JavaScript 時,實際上並不需要考慮記憶體。記憶體被抽象出來,你不會直接接觸到它。

取而代之的是 JS 引擎充當中介,為你管理記憶體。

比如說有一段 JS 程式碼用來建立一個變數(假設該 JS 程式碼使用了 React)。

JS 引擎利用編碼器把該值轉換成二進位制。

它將在記憶體中找到可以容納該二進位制的空間,這個過程稱為分配記憶體。

然後,引擎將跟蹤該變數是否仍然可以從程式中的任何地方訪問。如果該變數無法再訪問,以便 JS 引擎可以在回收的記憶體中存放新的值。

這種在記憶體中監控變數(字串、物件或其他型別)並釋放掉不再使用的變數所佔用的記憶體的過程,稱為垃圾回收。

像 JavaScript 這樣不直接處理記憶體的語言被稱為記憶體管理語言。

這種自動記憶體管理可以使開發人員更輕鬆。但它也增加了一些開銷,而這種開銷有時會使效能不可預測。

手動記憶體管理

和自動管理記憶體的語言相比,需要手動管理記憶體的語言有些不同。例如,我們來看看 React 如何使用 C 語言寫入記憶體(現在可以通過

WebAssembly實現)。

C 語言沒有 JavaScript 在記憶體上的抽象層。而是直接在記憶體上執行。你可以從記憶體載入東西,也可以將內容儲存到記憶體中。

當你將 C 語言或其他語言編譯到 WebAssembly 時,你使用的工具將在 WebAssembly 中新增一些輔助程式碼。例如,它會新增用於編碼和解碼位元組的程式碼。這些程式碼稱為執行環境。執行環境會處理一些本該 JS 引擎做的事情。

但是對於手動管理的語言,其執行時將不包括垃圾回收。

這並不意味著你完全要自己處理。即使在手動記憶體管理的語言中,通常會從語言執行時獲得一些幫助。例如,在 C 語言中,執行時會把哪些記憶體地址可用記錄在一張表中,這張表叫做空閒列表。

你可以使用函式malloc(記憶體分配的簡寫)來申請一些可以容納資料的記憶體地址。這將把這些地址從空閒列表中拿走。當你處理完這些資料後,你須呼叫函式free釋放掉由malloc函式申請的記憶體。之後,這些地址將被添加回空閒列表。

你必須弄清楚何時呼叫這些函式。這就是為什麼它被稱為手動記憶體管理——你得自己管理記憶體。

作為一名開發人員,弄清楚何時清除不同部分的記憶體可能很難。如果你在錯誤的時間進行操作,可能會出現bug,甚至導致安全漏洞。如果你不這樣做,你的記憶體就會耗盡。

這就是為什麼許多現代語言使用自動記憶體管理的原因——避免人為錯誤。但這是以效能為代價的。 我將在下一篇文章中更多地解釋這一點。