JavaScript垃圾回收機制

1.垃圾回收的概念

1.1 什么是垃圾回收機制:

GCGarbage Collection ,程序工作過程中會產生很多"垃圾",這些垃圾是程序不用的內存或者是之前用過了,以后不會再用的內存空間,而 GC 就是負責回收垃圾的,因為他工作在引擎內部,所以對于我們前端來說,GC 過程是相對比較無感的,這一套引擎執行而對我們又相對無感的操作也就是常說的 垃圾回收機制
不是所有語言都有 GC,一般的高級語言里面會自帶 GC,比如 Java、Python、JavaScript 等,也有無 GC 的語言,比如 C、C++ 等,那這種就需要我們程序員手動管理內存了,相對比較麻煩
在像 C/C++ 這樣的語言中,開發者需要手動分配(malloc)和釋放(free)內存。這種方式非常靈活,性能也高,但有兩個致命缺點:

  • 忘記釋放:會導致內存泄漏,程序占用的內存會隨著時間推移越來越多,最終可能導致程序崩潰或系統變慢。
  • 提前釋放:或釋放了多次,會導致懸掛指針,當程序嘗試訪問一個已經被釋放的內存地址時,會引發不可預知的錯誤(通常是程序崩潰)。

JavaScript中存在兩種變量:局部變量全局變量。全局變量的生命周期會持續到頁面卸載;而局部變量聲明在函數中,它的生命周期從函數執行開始,直到函數執行結束,在這個過程中,局部變量會在堆或棧中存儲它們的值,當函數執行結束后,這些局部變量不再被使用,它們所占有的空間就會被釋放。(不過,當局部變量被外部函數使用時,其中一種情況就是閉包,在函數執行結束后,函數外部的變量依然指向函數內部的局部變量,此時局部變量依然在被使用,所以不會回收。)

2.垃圾回收機制是如何實現的

2.1核心理念:

GC 機制的核心思想是可達性。簡單來說,就是判斷一個對象是否“可達”,如果不可達,它就是“垃圾”。

  • 可達的對象:以某種方式被訪問或使用的對象。
  • 不可達的對象:無法被訪問到的對象,可以被安全地回收。

GC 會有一系列的對象,它們是可達性的起點。在 JavaScript 中,主要的根包括:

全局對象:比如瀏覽器環境下的 window 對象,Node.js 環境下的 global 對象。
因為全局對象在應用程序的整個生命周期內都存在。只要你的網頁開著,window 對象就永遠不會消失。它是所有全局變量和內置API(如 setTimeout, localStorage)的宿主。如果它被回收了,整個JavaScript環境就都將崩塌。因此,全局對象是GC最重要、最基礎的一個“根”

函數調用棧:當前正在執行的函數中的局部變量和參數。
因為當前正在執行的代碼和它所依賴的數據,理所當然是“存活”的。調用棧代表了程序執行的“此時此刻”。如果這些正在使用的變量被回收了,程序將立即出錯。因此,調用棧中所有棧幀里的變量和參數,都被視為臨時的“根”。

活躍的 DOM 樹:頁面上存在的 DOM 元素。
因為DOM節點是構成用戶界面的實體。用戶能看到、能與之交互的元素,必須始終存在于內存中,瀏覽器需要依據它來進行繪制和響應事件。因此,所有在DOM樹上的節點都被認為是“可達的”。

垃圾回收器會從這些“根”出發,沿著引用鏈進行遍歷。所有能從“根”訪問到的對象,都會被認為是“活”的(可達的);反之,所有無法從“根”訪問到的對象,就會被認為是“死”的(不可達的),并成為垃圾回收的目標。

// 創建一個根對象,并被變量 user 引用
let user = {name: "Alice"
};// 原來的 { name: "Alice" } 對象失去了引用,因此它變成了不可達對象,等待被回收。
user = null;
2.2主流垃圾回收算法

瀏覽器通常使用的垃圾回收方法有兩種:標記清除引用計數

2.2.1標記清除

這是現代瀏覽器中最常用的垃圾回收算法。它完美地解決了循環引用的問題。

  • 原理:分為兩個階段:
    1. 標記階段:垃圾回收器從“根”對象開始,遍歷所有可達的對象,并在這些對象上打上一個“標記”,表示它們是存活的。
    2. 清除階段:垃圾回收器遍歷整個堆內存,所有沒有被標記的對象都被視為垃圾,并被回收,其占用的內存被釋放。
  • 優點:可以解決循環引用的問題。因為即使 objAobjB 互相引用,但如果它們都無法從“根”訪問到,那么它們就都不會被標記,最終會被一起清除。
function createCircularReference() {let objA = {};let objB = {};objA.b = objB; objB.a = objA; 
}createCircularReference();
  • 缺點
    • 執行效率問題:GC 執行時,需要暫停整個程序的運行,如果堆內存很大,標記和清除會很耗時。
    • 內存碎片化:清除后,會產生大量不連續的內存碎片。如果之后需要分配一個大對象,可能會因為沒有足夠大的連續空間而失敗。
2.2.2引用計數

這是早期的一種 GC 算法,思想非常簡單。

  • 原理:為每個對象維護一個“引用計數器”。當有一個引用指向該對象時,計數器加1;當引用被移除時,計數器減1。當計數器變為0時,表示該對象不再被需要,可以被回收。
  • 優點:實現簡單,垃圾可以被立即回收,不會有“暫停”的感覺。
  • 致命缺點:無法處理循環引用
    看下面的例子:

這種情況下,就要手動釋放變量占用的內存:

obj1.a =  null
obj2.a =  null
2.3 V8 引擎的優化:分代回收

為了解決標記-清除算法的效率問題,Google 的 V8 引擎(用于 Chrome 和 Node.js)采用了一種更先進的策略:分代回收
這個策略基于一個重要的觀察:“大部分對象都是朝生夕死的”。也就是說,很多對象在創建后很快就不再被使用,而少數對象會存活很長時間。

V8 將堆內存分為兩個主要區域:
新生代:Scavenge 算法

  • 特點:存放生命周期短的對象,空間較小(通常為 1-8MB),垃圾回收頻繁且速度快
  • 內部結構:新生代內存被平分為兩個相等的空間:From 空間(使用中)To 空間(空閑)
  • **回收過程:
    1. 新對象首先被分配在 From 空間。
    2. 當 From 空間快要被占滿時,觸發一次新生代的 GC。
    3. GC 會檢查 From 空間中的存活對象,并將它們復制到 To 空間。
    4. 復制完成后,From 空間剩下的所有對象都是垃圾。整個 From 空間被一次性清空。
    5. From 空間和 To 空間的角色互換,等待下一次 GC。
  • 晉升:如果一個對象在新生代中經過了多次 Scavenge 依然存活,那么它被認為是生命周期較長的對象,會被“晉升”到老生代中。此外,如果復制一個對象到 To 空間時,To 空間的使用率超過了25%,該對象也會被直接晉升到老生代。
    老生代:標記-清除與 標記-整理
  • 特點:存放生命周期長或體積大的對象,空間較大,GC 頻率較低
  • 回收過程
    1. 主要使用標記-清除算法,流程如前所述。
    2. 為了解決內存碎片化問題,V8 引入了標記-整理算法。它在標記階段之后,不是直接清除垃圾,而是將所有存活的對象向內存的一端移動,然后直接清理掉邊界之外的所有內存。這樣就得到了連續的空閑空間。

3.減少垃圾回收

3.1 手動處理:
雖然瀏覽器可以進行垃圾自動回收,但是當代碼比較復雜時,垃圾回收所帶來的代價比較大,所以應該盡量減少垃圾回收。

  • 數組進行優化: 在清空一個數組時,最簡單的方法就是給其賦值為[ ],但是與此同時會創建一個新的空對象,可以將數組的長度設置為0,以此來達到清空數組的目的。
  • 對象進行優化: 對象盡量復用,對于不再使用的對象,就將其設置為null,盡快被回收。

避免意外的全局變量
始終使用 constlet 聲明變量,開啟嚴格模式('use strict';)。

function leakyFunction() {// 如果沒有 'let' 或 'const', a 會被創建為全局變量// 它將永遠不會被回收,除非手動設為 nulla = new BigObject();
}

警惕閉包
閉包是 JavaScript 的強大特性,但也很容易造成內存泄漏。閉包可以使其父函數中的變量在函數執行結束后仍然存活。

function createClosure() {let largeData = new Array(1e6).fill('*'); // 這個返回的函數持有了對 largeData 的引用return function() {...return largeData.length;};
}let myClosure = createClosure();
// 即使 createClosure 執行完畢,largeData 也不會被回收,因為它被 myClosure 引用。
// 如果不再需要它,應手動解除引用。
myClosure = null;

定時器和事件監聽器
setInterval, setTimeoutaddEventListener 如果不被正確清理,它們的回調函數和其引用的外部變量都不會被回收。

let element = document.getElementById('my-button');
let largeData = new BigObject();function onClick() {// do something with largeData
}element.addEventListener('click', onClick);// 正確做法:
// element.removeEventListener('click', onClick);
// element = null;

在組件銷毀或元素移除時,務必使用 clearInterval, clearTimeoutremoveEventListener 清理掉相關的定時器和監聽器。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/92862.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/92862.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/92862.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

工業相機選擇規則

一、相機分辨率選擇相機分辨率指的是相機傳感器捕捉圖像細節的能力,具體來說就是傳感器上有效像素的總數量。可以把它理解為構成數字圖像的“小方塊”(像素)有多少個。工業領域內相機的分辨率的選擇根據更具產品需要的精度要求和產品大小來確…

【Web安全】csrf、ssrf和xxe的區別

CSRF、SSRF 和 XXE 是三種不同類型的網絡安全漏洞,它們的原理、攻擊目標、利用方式和危害場景均有顯著區別。以下從核心定義、原理、場景等維度詳細對比三者的差異。一、核心定義與原理對比漏洞類型全稱核心定義核心原理CSRF跨站請求偽造攻擊者誘導用戶在已登錄的情…

【Lua】XLua一鍵構建工具

將以下代碼放入Editor文件夾&#xff0c;點擊菜單欄的XLua/一鍵生成代碼和熱補丁 即可。using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEditor; using UnityEngine;/// <summary> /// XLua自動化構建工具 //…

20250808:EasyGBS 對接大華 ICC 平臺問題處理

最近有個現場在對接大華 ICC 平臺時&#xff0c;客戶反饋&#xff1a;EasyGBS 級聯成功&#xff0c;但 ICC 顯示下級離線。EasyGBS 成功對接過很多家國標平臺&#xff0c;但這種情況確實少見。我們遠程過去確認配置無誤后&#xff0c;就進行了抓包&#xff0c;拿到包我就納悶了…

js使用webscoket時使用自定義二進制包協議時并發問題處理

this.server new WebSocket.Server({ port: this.port });this.server.on(connection, (ws, req) > {const uniqueId dataUtil.uuid();ws.id uniqueId;global.serverSession.set(uniqueId, ws);logger.debug({ message: 客戶端已連接, traceId: ws.id, address: req.sock…

元數據管理與數據治理平臺:Apache Atlas 分類傳播 Classification Propagation

文中內容僅限技術學習與代碼實踐參考&#xff0c;市場存在不確定性&#xff0c;技術分析需謹慎驗證&#xff0c;不構成任何投資建議。Apache Atlas 框架是一套可擴展的核心基礎治理服務&#xff0c;使企業能夠有效、高效地滿足 Hadoop 中的合規性要求&#xff0c;并支持與整個企…

TSF應用開發與運維部署

架構演進歷程&#xff1a;單體架構-->SOA架構-->微服務架構-->Service Mesh騰訊微服務平臺TSF (Tencent Service Framework) 是一個圍繞應用和微服務的 PaaS 平臺。提供服務全生命周期管理能力和數據化運營支持。提供多維度應用、服務、機器的監控數據&#xff0c;助力…

linux開發之mmap內存映射

mmap概念 mmp是 將文件或設備直接映射到進程的虛擬內存空間 的一種機制&#xff0c;可實現程序像訪問內存一樣訪問文件&#xff0c;而不需要傳統的 read()/write()系統調用 文件內容被映射到進程的地址空間&#xff0c;讀寫文件就像操作內存一樣&#xff0c;操作系統負責自動同…

CPP繼承

繼承 一、繼承概述 1、為什么需要繼承 如下示例&#xff0c;Person 類、Student 類、Teacher 類有大量重復的代碼&#xff0c;造成代碼冗余&#xff0c;降低開發效率。我們可以通過繼承來解決這一問題。在面向對象的編程語言中&#xff0c;繼承是一個核心概念。主要作用將重復的…

模塊 PCB 技術在未來通信領域的創新突破方向

未來通信領域對數據傳輸速率、信號穩定性及設備集成度的要求持續攀升&#xff0c;模塊 PCB 作為通信設備的關鍵組件&#xff0c;其技術創新成為推動行業發展的核心動力。獵板 PCB 憑借深厚的技術積累與持續的研發投入&#xff0c;在模塊 PCB 技術創新方面取得諸多突破&#xff…

mysql的InnoDB索引總結

MySQL InnoDB索引知識點總結 1. 索引類型 1.1 聚簇索引&#xff08;Clustered Index&#xff09; 定義與特性 定義&#xff1a;聚簇索引是InnoDB的默認存儲方式&#xff0c;數據行按照主鍵的順序物理存儲在磁盤上特性&#xff1a; 每個InnoDB表只能有一個聚簇索引數據頁中的記錄…

C++模板的補充

類模板(上一篇沒講到類模板C/C內存管理&函數模板-CSDN博客&#xff09; 類模板的定義&#xff1a; template<class T1, class T2, ..., class Tn> class 類模板名 {// 類內成員定義 }; 用一個簡單的棧例子講類模板 #define _CRT_SECURE_NO_WARNINGS #include &l…

用JOIN替代子查詢的查詢性能優化

一、子查詢的性能瓶頸分析?重復執行成本?關聯子查詢會導致外層每行數據觸發一次子查詢&#xff0c;時間復雜度為O(M*N)sql-- 典型低效案例 SELECT e.employee_id, (SELECT d.department_name FROM departments d WHERE d.department_id e.department_id) FROM employees e; …

【設計模式】訪問者模式模式

訪問者模式&#xff08;Visitor Pattern&#xff09;詳解一、訪問者模式簡介 訪問者模式&#xff08;Visitor Pattern&#xff09; 是一種 行為型設計模式&#xff08;對象行為型模式&#xff09;&#xff0c;它允許你在不修改對象結構的前提下&#xff0c;為對象結構中的元素添…

比特幣現貨和比特幣合約的區別與聯系

一、基本定義項目現貨&#xff08;Spot&#xff09;合約&#xff08;Futures / Perpetual&#xff09;本質直接買賣比特幣本身買賣比特幣價格的衍生品合約所得資產真實的 BTC合約頭寸&#xff08;沒有直接持有 BTC&#xff09;結算方式交割比特幣現金結算&#xff08;多數平臺&…

Qt/C++開發監控GB28181系統/實時監測設備在線離線/視頻預覽自動重連/重新點播取流/低延遲

一、前言說明 一個好的視頻監控系統&#xff0c;設備掉線后能夠自動重連&#xff0c;也是一個重要的功能指標&#xff0c;如果監控系統只是個rtsp流地址&#xff0c;那非常好辦&#xff0c;只需要重新打開流地址即可&#xff0c;而gb28181中就變得復雜了很多&#xff0c;需要多…

此芯p1開發板使用OpenHarmony時llama.cpp不同優化速度對比(GPU vs CPU)

硬件環境 Cix P1 SoC 瑞莎星睿 O6 開發板 rx580顯卡 產品介紹&#xff1a; https://docs.radxa.com/orion/o6/getting-started/introduction OpenHarmony 5.0.0 使用vulkan后端的llama.cpp &#xff08;GPU&#xff09; # ./llama-bench -m /data/qwen1_5-0_5b-chat-q2_k.…

Android 四大布局:使用方式與性能優化原理

一、四大布局基本用法與特點1. LinearLayout&#xff08;線性布局&#xff09;使用方式&#xff1a;<LinearLayoutandroid:orientation"vertical" <!-- 排列方向&#xff1a;vertical/horizontal -->android:layout_width"match_parent"android:…

Redis的BigKey問題

Redis的BigKey問題 什么是大Key問題&#xff1f; 大key問題其實可以說是大value問題&#xff0c;就是某個key對應的value所占據的存儲空間太大了&#xff0c;所以導致我們在操作這個key的時候花費的時間過長&#xff08;序列化\反序列化&#xff09;&#xff0c;從而降低了redi…

TDengine IDMP 產品基本概念

基本概念 元素 (Element) IDMP 通過樹狀層次結構來組織數據&#xff0c;樹狀結構里的每個節點被稱之為元素 (Element)。元素是一個物理的或邏輯的實體。它可以是具體的物理設備&#xff08;比如一臺汽車&#xff09;&#xff0c;物理設備的一個子系統&#xff08;比如一臺汽車的…