JavaScript 記憶體管理及垃圾回收

来源:https://www.cnblogs.com/yuzhihui/archive/2023/01/22/17064331.html
-Advertisement-
Play Games

JavaScript 中的記憶體管理主要由 JavaScript 引擎負責,開發人員不需要手動管理記憶體。JavaScript 引擎使用垃圾回收演算法來實現自動垃圾回收。 JavaScript 垃圾回收演算法是指在 JavaScript 程式中,用來回收不再使用的記憶體的演算法。 ...


一、記憶體管理

JavaScript 是一種自動垃圾回收語言,這意味著 JavaScript 引擎會自動監測和清理無用的記憶體。

JavaScript 中的記憶體管理主要由 JavaScript 引擎負責,開發人員不需要手動管理記憶體。JavaScript 引擎使用垃圾回收演算法來實現自動垃圾回收。

二、垃圾回收

JavaScript 垃圾回收演算法是指在 JavaScript 程式中,用來回收不再使用的記憶體的演算法。常見的垃圾回收演算法包括:

  • 標記-清除演算法:標記出所有不再使用的對象,然後清除它們。
  • 引用計數演算法:維護每個對象的引用計數,當計數為0時回收對象。
  • 標記-整理演算法:標記出所有不再使用的對象,然後將所有存活的對象整理到一起,回收其他對象。
  • 增量標記-整理演算法:將垃圾回收過程分成多個小步驟執行,並且可以處理迴圈引用問題。

現代 JavaScript 引擎通常採用增量標記-整理演算法或其他類似演算法來實現垃圾回收。

1、標記-清除演算法

標記-清除演算法是通過標記未使用的記憶體塊,然後清除這些標記的記憶體塊來實現垃圾回收的。

標記-清除演算法的工作流程如下:

  1. 從根節點開始,遍歷所有可達的對象,將其標記為“可用”。
  2. 掃描記憶體中所有對象,將未被標記的對象標記為“不可用”。
  3. 清除所有不可用對象占用的記憶體。

標記-清除演算法的優缺點

優點:

  • 標記-清除演算法簡單易實現。
  • 標記-清除演算法可以回收任意類型的對象。

缺點:

  • 標記-清除演算法會產生碎片化的記憶體,這可能導致空間浪費。
  • 標記-清除演算法會產生暫停,這可能導致程式卡頓。

現在,由於標記-清除演算法會產生碎片化的記憶體和暫停,所以現代的 JavaScript 引擎主要使用增量標記-整理演算法來實現垃圾回收。增量標記-整理演算法將垃圾回收過程分成多個小步驟執行,避免了長時間的暫停。

標記-清除演算法是一種簡單易實現的垃圾回收演算法,但是會產生碎片化的記憶體和暫停,因此現在不再常用。

2、引用計數演算法

引用計數演算法是通過跟蹤每個對象的引用次數來確定對象是否被使用,如果一個對象的引用次數為0,則該對象被視為垃圾並被回收。

引用計數演算法的工作流程如下:

  1. 每當一個對象被引用時,將其引用計數增加1。
  2. 每當一個對象的引用被刪除時,將其引用計數減少1。
  3. 當一個對象的引用計數為0時,該對象被視為垃圾並被回收。

引用計數演算法的優缺點

優點:

  • 引用計數演算法可以實時回收垃圾。
  • 引用計數演算法可以較快地回收迴圈引用的對象。

缺點:

  • 引用計數演算法無法處理迴圈引用問題。如果兩個對象相互引用,而沒有其他變數引用它們,則它們的引用計數都為1,而它們都不能被回收。
  • 引用計數演算法會增加程式的運行時間和空間開銷。

引用計數演算法在處理迴圈引用問題上會有困難。而且引用計數演算法會增加程式的運行時間和空間開銷。因此現代的 JavaScript 引擎不再使用引用計數演算法來實現垃圾回收。

引用計數演算法的實現方式可以是各種各樣的, 例如:

  • 對於每一個對象都維護一個計數器,在有新的引用時將計數器加一,在引用結束時將計數器減一。
  • 對於每一個對象維護一個引用鏈表,在有新的引用時將引用的對象加入鏈表中,在引用結束時將引用的對象移除鏈表。

雖然現在的 JavaScript 引擎不再使用引用計數演算法來實現垃圾回收,但是對於引用計數演算法的理解對於理解其他演算法有很大幫助。

3、標記-整理演算法

標記-整理演算法是一種垃圾回收演算法,它首先標記出所有不再使用的對象,然後將所有存活的對象整理到一起,回收其他對象。

標記-整理演算法的工作流程如下:

  1. 標記:從根節點開始,遍歷所有可達的對象,將其標記為“存活”。
  2. 整理:將所有存活的對象移動到一起,以便進行回收。
  3. 回收:回收所有未被標記的對象占用的記憶體。

標記-整理演算法的優缺點

優點:

  • 可以有效地處理迴圈引用問題。
  • 可以減少記憶體碎片化。

缺點:

  • 整理過程會影響性能。
  • 需要額外的空間來存儲活動對象和空閑對象。

標記-整理演算法在處理迴圈引用問題上會有優勢,減少記憶體碎片化,但是會影響性能,需要額外的空間來存儲活動對象和空閑對象。

標記-整理演算法是一種較為新的垃圾回收演算法,相對於標記-清除演算法和引用計數演算法而言,它可以更好地解決迴圈引用問題。

在使用標記-整理演算法進行垃圾回收時,系統會標記出所有仍然在使用的對象,然後將這些對象移動到一起,這樣就可以避免記憶體碎片化,並且可以減少迴圈引用問題的影響。

但是,標記-整理演算法也有缺點,整理過程會影響性能,需要額外的空間來存儲活動對象和空閑對象。另外,在 JavaScript 引擎中,這種演算法也沒有得到廣泛採用,大多數 JavaScript 引擎使用的是增量標記-整理演算法或其他類似演算法。

4、增量標記-整理演算法

現代的 JavaScript 引擎主要使用增量標記-整理演算法來實現垃圾回收,這種演算法在運行時將垃圾回收過程分成多個小步驟來執行,避免了長時間的暫停。

增量標記-整理演算法的工作流程如下:

  1. 標記:從根節點開始,遍歷所有可達的對象,將其標記為“存活”。
  2. 整理:將所有未被標記的對象移動到一起,以便進行回收。
  3. 回收:回收所有未被標記的對象占用的記憶體。

增量標記-整理演算法通過將垃圾回收過程分成多個小步驟執行,來避免了長時間的暫停。這樣可以在不影響用戶體驗的情況下進行垃圾回收。

增量標記-整理演算法的優缺點

優點:

  • 避免了長時間的暫停,提高了程式的響應性。
  • 增量標記-整理演算法可以有效地處理迴圈引用問題。

缺點:

  • 由於增量標記-整理演算法是一種標記-整理演算法,所以會產生碎片化的記憶體,這可能降低記憶體利用率。
  • 增量標記-整理演算法的實現需要額外的空間來存儲活動對象和空閑對象。

增量標記-整理演算法是基於標記-清除演算法和標記-整理演算法的結合體。它首先使用標記-清除演算法找出所有存活的對象,然後使用標記-整理演算法將這些對象移動到一起,以便進行回收。

三、優化措施

JavaScript 中針對垃圾回收的優化措施有很多,主要有如下幾種:

  1. 避免迴圈引用迴圈引用是 JavaScript 垃圾回收中常見的問題,為了避免這種問題,開發人員應該儘量避免在不同對象之間建立迴圈引用關係。

  2. 儘早釋放不再使用的對象儘早釋放不再使用的對象可以減少垃圾回收的工作量,進而提高性能。例如,在不再使用的時候將變數賦值為 null 或 undefined,可以幫助 JavaScript 引擎更快地找到垃圾。

  3. 避免使用全局變數全局變數會一直存在,如果不需要使用,就應該儘早釋放。

  4. 避免使用長作用域鏈長作用域鏈會導致 JavaScript 引擎花費更多的時間來跟蹤對象的存活狀態,因此應該儘量避免使用長作用域鏈。

  5. 使用 WeakMap 和 WeakSetWeakMap 和 WeakSet 可以幫助我們維護對象之間的弱引用關係,可以減少迴圈引。

  6. 使用 requestIdleCallbackrequestIdleCallback 允許我們在瀏覽器空閑時執行一些任務,可以幫助我們在不影響用戶體驗的情況下進行垃圾回收。

 

需要註意的是,JavaScript 中的垃圾回收並不能保證程式一定不會出現記憶體泄漏的情況,例如迴圈引用,開發人員需要知道這種情況並採取對應的處理措施。

應對迴圈引用問題的處理措施?

JavaScript 中的迴圈引用是指兩個或多個對象之間相互引用的情況。這種情況下,這些對象就不能被垃圾回收機制正常回收,會導致記憶體泄漏。

解決迴圈引用問題主要有以下幾種方法:

  1. 使用 WeakMap 和 WeakSet:WeakMap 和 WeakSet 可以幫助我們維護對象之間的弱引用關係,可以減少迴圈引用問題。

  2. 使用計數器:對於某些情況,通過維護對象之間的引用計數可以幫助我們解決迴圈引用問題。

  3. 使用雙向鏈表:雙向鏈表可以幫助我們解決迴圈引用問題,可以支持對象之間相互引用,但是需要手動維護對象之間的關係。

  4. 避免迴圈引用:是最簡單而有效的解決辦法,開發人員應該儘量避免在不同對象之間建立迴圈引用關係。

  5. 使用第三方庫:使用第三方庫也可以幫助我們解決迴圈引用問題,如 cycle.js

  6. 使用設置空值的方法:在不再使用某個對象時,將其設置為空值可以消除對該對象的引用。

  7. 使用閉包:閉包可以在函數執行結束後銷毀其所引用的對象。

  8. 使用 IIFE:IIFE(立即執行函數表達式)可以在函數執行結束後立即銷毀其所引用的對象。

  9. 使用 WeakRef:WeakRef是一種弱引用對象,它不會影響到對象的存活狀態,可以使用它來消除迴圈引用。

需要註意的是, 在使用這些方法解決迴圈引用問題時, 還需要考慮到代碼複雜度和可維護性, 在使用時應該慎重考慮。

 

JavaScript 中沒有強制垃圾回收的方法,也沒有手動釋放記憶體的方法, JavaScript 引擎會根據需要自動進行垃圾回收。

在 JavaScript 中,當一個對象不再被任何變數引用時,它就會被視為垃圾並被回收。需要註意的是,JavaScript 中的垃圾回收僅針對不再使用的記憶體,而不是不再使用的變數。例如,如果一個變數存儲的是對象的引用,則該對象可能不再被其他變數引用,但仍然可能被使用。

總之,JavaScript 中的記憶體管理主要由 JavaScript 引擎負責,開發人員不需要手動管理記憶體。JavaScript 中的垃圾回收是自動進行的,開發人員只需要瞭解垃圾回收機制並採取優化措施,就可以幫助程式更好的管理記憶體。

作者:yuzhihui
出處:http://www.cnblogs.com/yuzhihui/ 聲明:歡迎任何形式的轉載,但請務必註明出處!!!
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一群高智商青年在餐廳吃飯,餐桌上一個瓶蓋標識為鹽的瓶子里裝得是胡椒粉,而標識為胡椒粉的瓶子里裝得卻是鹽,他們想出了一個充滿才氣的方案來完成對調--僅需要一張餐巾紙、一根吸管和兩個空碟子。當他們叫來服務員,準備炫耀他們的天才想法時,只見服務員什麼也沒說,只是拿起鹽瓶和胡椒粉瓶,互換了瓶蓋…… 在我們... ...
  • 2023-01-21 一、攔截器與過濾器的區別 1、過濾器(Filter)屬於web伺服器組件 (1)過濾器主要作用:過濾Servlet請求 (2)執行時機:兩處執行時機(Servlet前、Servlet後) 2、攔截器(Interceptor)屬於框架(springMVC) (1)攔截器主要作用: ...
  • Spring管理Bean-IOC-05 3.基於註解配置bean 3.3自動裝配 基本說明: 基於註解配置bean,也可以實現自動裝配,使用的註解是:@AutoWired或者@Resource @AutoWired 的規則說明 (1)在IOC容器中查找待裝配的組件的類型,如果有唯一的bean裝配(按 ...
  • 前言 質數歷來都是數學界的寵兒,是數學里神秘的謎團。 質數又和 C 語言有著不解之緣,本篇文章將講解如何用 C 語言判斷質數。 為了方便大家在讀完此文章後使用文中程式,我會將判斷質數的程式封裝成函數,此函數的功能是:判斷形參 _number 是否是質數,若 _number 是質數,則返回 1;若不是 ...
  • 2023-01-21 一、文件下載 1、實現文件下載步驟 (1)準備文件下載相關步驟 (2)將ResponseEntity<T>對象,作為方法返回值 (3)為ResponseEntity<T>對象,設置三個參數 2、示例代碼 @RequestMapping("/fileDownloadControl ...
  • 開心一刻 有一天,qq收到一個好友申請,驗證消息上寫的是:哥哥加我,我是妹妹 我以為是性騷擾,就沒加,直接回了一句:我喜歡少婦 過了一會兒,姑姑就給我打了個電話:你妹妹qq加你,你怎麼不同意,她想問你幾道數學題,你說你喜歡少婦 我:姑姑,你聽我狡辯一下...... 祝大家除夕快樂! 節點準備 基於  ...
  • JavaScript 中的繼承可以通過多種方式來實現,如原型鏈繼承、借用構造函數繼承、組合繼承、ES6 Class繼承等。 ...
  • 兔年到了,祝大家身體健,康萬事順利。本文內容作為兔年新春紀念頁面,將使用 Three.js 及 其他前端開發知識,創建一個以兔子為主題的 3D 簡單的趣味頁面 Rabbit craft go。本文內容包括使用純代碼創建三維浮島、小河、樹木、兔子、胡蘿蔔以及兔子的運動交互、浮島的動畫效果等。本文包含的... ...
一周排行
    -Advertisement-
    Play Games
  • 前言 在我們開發過程中基本上不可或缺的用到一些敏感機密數據,比如SQL伺服器的連接串或者是OAuth2的Secret等,這些敏感數據在代碼中是不太安全的,我們不應該在源代碼中存儲密碼和其他的敏感數據,一種推薦的方式是通過Asp.Net Core的機密管理器。 機密管理器 在 ASP.NET Core ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 順序棧的介面程式 目錄順序棧的介面程式頭文件創建順序棧入棧出棧利用棧將10進位轉16進位數驗證 頭文件 #include <stdio.h> #include <stdbool.h> #include <stdlib.h> 創建順序棧 // 指的是順序棧中的元素的數據類型,用戶可以根據需要進行修改 ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • C總結與剖析:關鍵字篇 -- <<C語言深度解剖>> 目錄C總結與剖析:關鍵字篇 -- <<C語言深度解剖>>程式的本質:二進位文件變數1.變數:記憶體上的某個位置開闢的空間2.變數的初始化3.為什麼要有變數4.局部變數與全局變數5.變數的大小由類型決定6.任何一個變數,記憶體賦值都是從低地址開始往高地 ...
  • 如果讓你來做一個有狀態流式應用的故障恢復,你會如何來做呢? 單機和多機會遇到什麼不同的問題? Flink Checkpoint 是做什麼用的?原理是什麼? ...
  • C++ 多級繼承 多級繼承是一種面向對象編程(OOP)特性,允許一個類從多個基類繼承屬性和方法。它使代碼更易於組織和維護,並促進代碼重用。 多級繼承的語法 在 C++ 中,使用 : 符號來指定繼承關係。多級繼承的語法如下: class DerivedClass : public BaseClass1 ...
  • 前言 什麼是SpringCloud? Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發便利性簡化了分散式系統的開發,比如服務註冊、服務發現、網關、路由、鏈路追蹤等。Spring Cloud 並不是重覆造輪子,而是將市面上開發得比較好的模塊集成進去,進行封裝,從 ...
  • class_template 類模板和函數模板的定義和使用類似,我們已經進行了介紹。有時,有兩個或多個類,其功能是相同的,僅僅是數據類型不同。類模板用於實現類所需數據的類型參數化 template<class NameType, class AgeType> class Person { publi ...
  • 目錄system v IPC簡介共用記憶體需要用到的函數介面shmget函數--獲取對象IDshmat函數--獲得映射空間shmctl函數--釋放資源共用記憶體實現思路註意 system v IPC簡介 消息隊列、共用記憶體和信號量統稱為system v IPC(進程間通信機制),V是羅馬數字5,是UNI ...