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
  • 下麵是一個標準的IDistributedCache用例: public class SomeService(IDistributedCache cache) { public async Task<SomeInformation> GetSomeInformationAsync (string na ...
  • 這個庫提供了在啟動期間實例化已註冊的單例,而不是在首次使用它時實例化。 單例通常在首次使用時創建,這可能會導致響應傳入請求的延遲高於平時。在註冊時創建實例有助於防止第一次Request請求的SLA 以往我們要在註冊的時候實例單例可能會這樣寫: //註冊: services.AddSingleton< ...
  • 最近公司的很多項目都要改單點登錄了,不過大部分都還沒敲定,目前立刻要做的就只有一個比較老的項目 先改一個試試手,主要目標就是最短最快實現功能 首先因為要保留原登錄方式,所以頁面上的改動就是在原來登錄頁面下加一個SSO登錄入口 用超鏈接寫的入口,頁面改造後如下圖: 其中超鏈接的 href="Staff ...
  • Like運算符很好用,特別是它所提供的其中*、?這兩種通配符,在Windows文件系統和各類項目中運用非常廣泛。 但Like運算符僅在VB中支持,在C#中,如何實現呢? 以下是關於LikeString的四種實現方式,其中第四種為Regex正則表達式實現,且在.NET Standard 2.0及以上平... ...
  • 一:背景 1. 講故事 前些天有位朋友找到我,說他們的程式記憶體會偶發性暴漲,自己分析了下是非托管記憶體問題,讓我幫忙看下怎麼回事?哈哈,看到這個dump我還是非常有興趣的,居然還有這種游戲幣自助機類型的程式,下次去大玩家看看他們出幣的機器後端是不是C#寫的?由於dump是linux上的程式,剛好win ...
  • 前言 大家好,我是老馬。很高興遇到你。 我們為 java 開發者實現了 java 版本的 nginx https://github.com/houbb/nginx4j 如果你想知道 servlet 如何處理的,可以參考我的另一個項目: 手寫從零實現簡易版 tomcat minicat 手寫 ngin ...
  • 上一次的介紹,主要圍繞如何統一去捕獲異常,以及為每一種異常添加自己的Mapper實現,並且我們知道,當在ExceptionMapper中返回非200的Response,不支持application/json的響應類型,而是寫死的text/plain類型。 Filter為二方包異常手動捕獲 參考:ht ...
  • 大家好,我是R哥。 今天分享一個爽飛了的面試輔導 case: 這個杭州兄弟空窗期 1 個月+,面試了 6 家公司 0 Offer,不知道問題出在哪,難道是杭州的 IT 崩盤了麽? 報名面試輔導後,經過一個多月的輔導打磨,現在成功入職某上市公司,漲薪 30%+,955 工作制,不咋加班,還不捲。 其他 ...
  • 引入依賴 <!--Freemarker wls--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.30</version> </dependency> ...
  • 你應如何運行程式 互動式命令模式 開始一個互動式會話 一般是在操作系統命令行下輸入python,且不帶任何參數 系統路徑 如果沒有設置系統的PATH環境變數來包括Python的安裝路徑,可能需要機器上Python可執行文件的完整路徑來代替python 運行的位置:代碼位置 不要輸入的內容:提示符和註 ...