1. 程式人生 > 其它 >JS進階之記憶體管理

JS進階之記憶體管理

技術標籤:JS進階javascript

本篇為JavaScript進階系列知識點的第一篇部落格,只要介紹關於JavaScript的記憶體管理相關知識,希望通過分享來提升對知識點的認識和自身自控力

文章目錄

一、前端為什麼要關注記憶體

  1. 任何一個程式的執行都需要記憶體,對於一個頁面來說,沒有及時釋放不再使用的記憶體,這種現象稱為記憶體洩漏。
  2. 一次記憶體洩漏似乎影響不大,但記憶體堆積會造成記憶體溢位,記憶體溢位簡單來說,我們所需要的記憶體空間大於可用記憶體,此時我們的程式就會出現記憶體溢位錯誤,造成網頁長時間無響應或崩潰。
  3. 本質上講,記憶體洩漏就是由於疏忽或錯誤造成程式未能釋放哪些已經不再使用的堆記憶體,造成記憶體的浪費。

二、垃圾回收機制

  1. 像C語言這樣的底層語言一般都有底層的記憶體管理介面,比如 malloc()和free()用於分配記憶體和釋放記憶體。
  2. 而對於JavaScript來說,會在建立變數(物件,字串等)時分配記憶體,並且在不再使用它們時“自動”釋放記憶體,這個自動釋放記憶體的過程稱為垃圾回收
  3. 找出那些不再繼續使用的變數,然後釋放其所佔用的記憶體,垃圾回收器會按照的固定時間間隔週期性執行這一操作

三、垃圾回收機制優缺點

  • JavaScript使用垃圾回收機制來自動管理記憶體,垃圾回收是一把雙刃劍;
  1. 優點: 可以大幅簡化程式的記憶體管理程式碼,降低程式設計師的負擔,減少因長時間運轉而帶來的記憶體洩露問題
  2. 缺點: 意味著程式設計師將無法掌控記憶體,JavaScript沒有暴露任何關於記憶體的API.我們無法強迫其進行垃圾回收,更無法干預記憶體管理

四、記憶體生命週期

在這裡插入圖片描述

  1. 分配記憶體: 當我們申明變數、函式、物件時,系統會自動為他們分配記憶體
  2. 使用記憶體: 就是使用變數、函式
  3. 釋放記憶體: 使用完畢,由垃圾回收機制自動回收不再使用的記憶體

五、垃圾回收機制之回收策略

  • 現在各大瀏覽器通常用採用的垃圾回收有兩種方法:標記清除、引用計數

01-引用計數 (reference counting)

  1. 定義: 跟蹤記錄每個值被引用的次數,如果一個值的引用次數是0,就表示這個值不再用到了,因此可以將這塊記憶體釋放
  2. 原理: 每次引用加一,被釋放時減一,當這個值的引用次數變成0時,就可以將記憶體空間回收
  3. 例項:
1 const obj = { a:10 }; // 引用+1 
2 const obj1 = { a:10 }; // 引用+1
3 const obj = {}; //引用減1
4 const obj = null; // 引用為0
  • 過程
    1. 聲明瞭一個變數並將一個引用型別的值賦值給這個變數,這個引用型別的值的引用次數是1
    2. 同一個值又被賦值給另一個變數,這一引用型別值的引用次數加1
    3. 當包含這個引用型別值的變數又被賦值成另一個值了,那麼這個引用型別值的引用次數減1
    4. 當引用次數變成0時,說明沒辦法訪問這個值了
    5. 當垃圾收集器下一次執行時,它就會釋放引用次數是0的值所佔的記憶體
  1. 存在大問題 – 迴圈引用無法回收
    // 迴圈引用
    function fn() {
        var objA = { a: 10 };
        var objB = { b: 10 };
        objA.c = objA;
        objB.d = objB;
    }
    

iE8之前遊覽器存在這個問題,現在主流遊覽器幾乎採用標記清除

02-標記清除

  1. 定義

    1. 標記清除指的是當變數進入環境時,這個變數標記為 “進入環境”;
    2. 而當變數離開環境時,則將其標記為"離開環境";
    3. 最後,垃圾收集器完成記憶體清除工作,銷燬那些帶標記的值並回收他們所佔用的記憶體空間;
    4. 目前主流遊覽器都是標記清除,只是時間不同
    	function foo () {
        var a = 10; // 被標記進入環境
        var b = 'hello'; // 被標記進入環境
    	}
    	foo(); // 執行完畢,a 和 b 被標記離開環境,記憶體被回收
    
  2. 執行環境

    • 執行環境定義了變數或函式有權訪問的其他資料,決定了他們各自的行為。
    • 每個執行環境都有一個與之關聯的變數物件(variable object), 環境中定義的所有變數和函式都儲存在這個物件中,
    • 解析器會識別標記這些環境
  3. 全域性執行環境

    • 最外圍的一個執行環境
    • 根據宿主環境不同表示執行環境的物件不一樣。在遊覽器中,全域性執行環境被認為是Window物件
    • 全域性變數和函式都是作為window物件的屬性和方法建立的
    • 某個執行環境中所有的程式碼執行完畢後,該環境被銷燬,儲存在其中的所有變數和函式定義也隨之銷燬
    • 全域性直到應用程式結束,例如: 關閉網頁或遊覽器
  4. 環境棧 (區域性)

    • 每個函式都有自己的執行環境。
    • 當執行流進入一個函式時,函式的環境就會被推入一個環境棧中。
    • 而在函式執行之後,棧將其環境彈出,把控制權返回給之前的執行環境。
    • ECMAScript程式中的執行流正是這個方標的機制控制著

六、記憶體的佔用

  • Chrome 瀏覽器檢視記憶體佔用,按照以下步驟操作。
    在這裡插入圖片描述
1. 開啟開發者工具,選擇 Memory 面板
2. 點選左上角的錄製按鈕。
3. 在頁面上進行各種操作,模擬使用者的使用情況。
4. 一段時間後,點選對話方塊的 stop 按鈕,面板上就會顯示這段時間的記憶體佔用情況。

寫在最後的話: 自律就是自己知道想要什麼,並且足夠強烈