記錄--JS 的垃圾回收機制

来源:https://www.cnblogs.com/smileZAZ/archive/2023/08/16/17635894.html
-Advertisement-
Play Games

這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 垃圾回收(Garbage Collection)是一種記憶體管理機制,用於檢測和清理不再被程式使用的記憶體,這些不再被使用的記憶體就被稱為垃圾。垃圾回收器會在 JS 引擎(瀏覽器或者 nodejs)內部周期性地運行,一般情況下無需開發者手 ...


這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

前言

垃圾回收(Garbage Collection)是一種記憶體管理機制,用於檢測和清理不再被程式使用的記憶體,這些不再被使用的記憶體就被稱為垃圾。垃圾回收器會在 JS 引擎(瀏覽器或者 nodejs)內部周期性地運行,一般情況下無需開發者手動操作。

但是,瞭解垃圾回收機制的工作原理有助於我們寫出更加高效的 JS 代碼,使 JS 引擎更好的幫助我們完成垃圾回收,避免我們開發的應用出現記憶體泄漏問題。

垃圾是怎樣產生的?

JS 中的數據類型有原始類型和引用類型,原始類型占用的記憶體極小,一般是字元串、數字、布爾值這些,他們被存放在棧(stack)中。引用類型可以是數組、普通對象或者函數,他們一般會包含較多的數據,所以引用類型的實際數據存放在記憶體的堆(heap)中,然後在棧中會存放一個指向該實際數據的地址。

const str = "abc" // 原始類型
const obj = { foo: "bar" } // 引用類型

在 JS 中每聲明一個變數,該應用占用的記憶體就會相應的增加,但機器的記憶體是有限的,記憶體的占用不能無限制的增加。所以 JS 引擎需要適時的回收記憶體,釋放記憶體,保留性能,從而運行使程式流暢運行。

垃圾回收機制會回收哪些垃圾?

當一個對象不在任何引用被引用時,它就變得不可達,垃圾回收器就需要將這些不可達對象標記為可回收,併在適當的時機回收它們的記憶體。

以下麵這段代碼為例:

function myFunction() {
  const obj = { foo: "bar" }
  // do something
}

myFunction()

這段代碼中的 obj 對象在 myFunction 函數執行之後,就已經沒有被引用了,就需要被回收。

但當某個對象從開發角度上來說不再被使用了,卻意外的仍然在某個地方被引用,垃圾回收器就無法回收它的記憶體,就會造成記憶體泄漏(記憶體逐漸累積,程式占用的記憶體越來越多,當超過系統的可用記憶體時,就會造成程式崩潰)。

比如下麵這段代碼中 obj 對象就可能不會被回收:

function myFunction() {
  const obj = { foo: "bar" }

  setTimeout(() => {
    console.log(obj.foo)
  }, 1000)
}

myFunction()

因為 obj 作為閉包中的引用傳遞給了定時器的回調函數,即使 myFunction 執行完畢,由於定時器沒有被清除,obj 仍然被定時器回調函數持有引用,就可能導致 obj 不會被垃圾回收。

垃圾回收的演算法

JavaScript 中的垃圾回收機制主要基於以下兩個原則:

引用計數(Reference Counting)

每個對象都有一個引用計數,用於記錄有多少個引用指向該對象。當引用計數變為零時,表示沒有任何引用指向該對象,因此該對象可以被回收。

標記-清除(Mark and Sweep)

這是一種更常見的垃圾回收演算法。它從根對象(如全局對象、當前執行上下文中的變數等)開始,通過遍歷對象之間的引用關係,標記所有可達的對象。然後,回收器會清除未標記的對象,即不可達的對象,釋放其記憶體。

Chrome 和 nodejs 的垃圾回收演算法

Chrome 和 nodejs 都採用了谷_歌開源的 V8 引擎。V8 引擎的垃圾回收機制採用了標記清除演算法,但在此基礎又做了一些優化。

V8 引擎將記憶體分為新生代(Young Generation)和老生代(Old Generation)。大多數對象在新生代中創建,經過一定時間後,如果它們仍然存活,就會被晉升到老生代。

Scavenger 垃圾回收(新生代)

新生代使用了 Scavenger 垃圾回收演算法,它將記憶體劃分為一個存活區域和一個空閑區域。對象首先被分配到存活區域,當存活區域滿時,會執行垃圾回收操作,將存活的對象複製到空閑區域,並清空存活區域。

Mark-Sweep-Compact 垃圾回收(老生代)

老生代中使用了 Mark-Sweep-Compact(標記-清除-整理)垃圾回收演算法。它首先標記所有的存活對象,然後清除掉未被標記的對象,最後進行記憶體整理,使存活對象連續排列,減少記憶體碎片。

增量垃圾回收

V8 引擎還支持增量垃圾回收。他會將垃圾回收操作分成多個小步驟執行,每個步驟之間會插入一些 JavaScript 代碼的執行,從而避免長時間的垃圾回收造成的界面卡頓。

空閑時間垃圾回收

V8 引擎還在空閑時間執行部分垃圾回收操作,以充分利用閑置的計算資源。這些時間段可能是在程式等待用戶輸入、網路請求返回、或者其他暫時沒有任務需要處理的情況下出現的。

需要手動清除的記憶體

垃圾回收機制會根據演算法智能的回收大部分的記憶體,但由於業務邏輯的關係,它無法明確知道在我們的寫的(垃圾)代碼中,哪些對象其實是不再使用的,所以我們在開發過程中需要及時的清除不需要的事件監聽、定時器、計時器,避免迴圈引用,以及避免使用閉包。

清除事件監聽

const myButton = document.getElementById("myButton")

function handleClick() {
  console.log("Button clicked!")
}

// 添加事件監聽器
myButton.addEventListener("click", handleClick)

// 在頁面卸載或元素移除時解除事件監聽器
window.addEventListener("beforeunload", () => {
  myButton.removeEventListener("click", handleClick)
})

執清除定時器、計時器

const timer = setTimeout(() => {}, 500)

// 在頁面卸載或元素移除時解除事件監聽器
window.addEventListener("beforeunload", () => {
  clearTimeout(timer)
})

手動調用垃圾回收

一般情況下我們無需手動調用垃圾回收,但有些瀏覽器支持主動觸發垃圾回收。

IE 瀏覽器

if (typeof window.CollectGarbage === "function") {
  window.CollectGarbage()
}

Opera 瀏覽器

if (window.opera && typeof window.opera.collect === "function") {
  window.opera.collect()
}

本文轉載於:

https://juejin.cn/post/7267434484505788468

如果對您有所幫助,歡迎您點個關註,我會定時更新技術文檔,大家一起討論學習,一起進步。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • # 二進位包安裝mysql ## 準備 1.先查看系統中是否已存在mysql,存在將其卸載 ``` rpm -qa mysql rpm -qa mariadb yum remove xxx -y ``` 2.環境清理 清空PATH有關的mysql 註釋掉之前的$PATH 沒有就跳過這步 ``` #e ...
  • 為什麼需要設備驅動模型 內核版本發展 2.4版本之前內核沒有統一的設備驅動模型,但是可以用(例如先前的led字元設備驅動實驗,使用前需要手動調用mknod命令創建設備文件,從而進一步控制硬體)。 2.4~2.6版本內核使用devfs,掛載在/dev目錄。需要在內核驅動中創建設備文件(調用devfs_ ...
  • 本文是紅帽RHCE考題的總結,個別題目寫了多種步驟。 一、安裝和配置ansible 題目: 按照下方所述,在控制節點 bastion.lab.example.com 上安裝和配置 Ansible: 安裝所需的軟體包 創建名為/home/devops/ansible/inventory 的靜態清單文件 ...
  • 哈嘍大家好,我是鹹魚 今天我們來看一個關於 `Keepalived` 檢測腳本無法執行的問題 一位粉絲後臺私信我,說他部署的 `keepalived` 集群 `vrrp_script` 模塊中的腳本執行失敗了,但是手動執行這個腳本卻沒有任何問題 ![image](https://img2023.cn ...
  • ![](https://img2023.cnblogs.com/blog/3076680/202308/3076680-20230815140125196-1561757678.png) # 1. 服務級別幫助你定義客戶滿意的程度和標準,以便你在解決性能、可擴展性挑戰等事情與開發內部工具之間做出時間 ...
  • ## 一、引言 ### 1.1 什麼是MySQL Shell ? MySQL Shell 是 MySQL 的一個高級客戶端和代碼編輯器,是第二代 MySQL 客戶端。第一代 MySQL 客戶端即我們常用的 MySQL 。除了提供類似於 MySQL 的 SQL 功能外,MySQL Shell 還提供 ...
  • 本文將重點介紹Flutter中圖片的載入原理,使用過程中有哪些需要註意的地方及優化思路和手段,希望能給大家帶來一些啟發和幫助。 ...
  • 加拿大創新、科學和經濟發展部(ISED)已更新和發佈RSS-247 Issue 3標準,取代RSS-247 Issue 2標準。自 Issue 3於發佈之日起 6個月為過渡期,過渡期內Issue 2和Issue 3兩個版本均可使用,過渡期(2023.8.3-2024.2.2)後,僅接受Issue 3 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...