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
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...