溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JS中的垃圾回收機制怎么理解

發(fā)布時間:2023-03-06 10:09:20 來源:億速云 閱讀:113 作者:iii 欄目:web開發(fā)

這篇“JS中的垃圾回收機制怎么理解”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“JS中的垃圾回收機制怎么理解”文章吧。

基本類型存放在棧中,引用類型存放在堆中。JavaScript 是在創(chuàng)建變量(對象,字符串等)時自動進行了分配內(nèi)存,并且在不使用它們時“自動”釋放。釋放的過程稱為垃圾回收。

垃圾回收策略

所有垃圾回收器都需要做的任務

  • 標記空間中活動(存活)對象和非活動(非存活)對象

  • 回收或者重用被非活動對象占據(jù)的內(nèi)存

  • 內(nèi)存整理,防止內(nèi)存碎片的出現(xiàn)

什么是垃圾對象?

一般來說沒有被引用的對象就是垃圾,就是要被清除。從根開始遍歷對象。

例外
如果幾個對象引用形成一個環(huán),互相引用,但根訪問不到它們,這幾個對象也是垃圾,也要被清除。

什么是根對象和存活對象

根對象
有一組基本的固有可達值,由于顯而易見的原因無法刪除

  • 全局變量 window全局對象、DOM文檔樹根對象等

存活對象
如果引用或引用鏈可以從根訪問任何其他值,則認為該值是可訪問的

V8引擎回收 分代回收法

將堆分為新生代和老生代。
新生代中存放的是生存時間短的對象,老生代中存放的生存時間久的對象。

新生代垃圾回收器 scavenge復制算法

堆內(nèi)存分為兩部分,一個是使用區(qū),處于使用狀態(tài)的空間;另一個是空閑區(qū),處于空閑狀態(tài)的空間。

JS中的垃圾回收機制怎么理解

  • 新加入的對象會存放到使用區(qū),當使用區(qū)快被寫滿時,就需要進行垃圾清理操作。

  • 新生代垃圾回收器會對使用區(qū)的活動對象對象做標記,標記完成之后將使用區(qū)的活動對象復制到空閑區(qū)。解決了內(nèi)存散落分塊的問題。

  • 將使用區(qū)的非活動對象占用的空間清理掉。最后進行角色互換,原來的使用區(qū)變成新的空閑區(qū),原來的空閑區(qū)變成新的使用區(qū)。

移動到老生代的對象

  • 如果一個對象多次復制后仍然存活,將被認為時生命周期較長的對象,隨后被移動到老生代中。

  • 復制一個對象到空閑區(qū)時,占用空閑區(qū)空間超過了25%,這個對象會被直接晉升到老生代空間中。原因是原來的空閑區(qū)會變成新的使用區(qū),繼續(xù)進行對象內(nèi)存的分配,若占比過高,新對象的可用空間太少。

新生代優(yōu)化 并行回收

全停頓問題
JavaScript是單線程語言,運行在主線程上,進行垃圾回收時會阻塞JavaScript腳本的執(zhí)行,需要等待垃圾回收完畢后再恢復腳本執(zhí)行。

如果一次GC的時間過長,可能造成頁面卡頓現(xiàn)象。

并行回收機制
垃圾回收器在主線程上執(zhí)行的過程中,開啟多個輔助線程,同時執(zhí)行同樣的回收工作。

JS中的垃圾回收機制怎么理解

老生代垃圾回收

使用scavenge方式存在的問題
1.存活對象較多,頻繁復制存活對象效率將降低
2.浪費一半空間

主要采用標記-清除法,在內(nèi)存分配不足時,采用標記-整理

老年代垃圾回收期采用的算法
1. 首先使用標記-清除完成垃圾空間的回收;
2. 采用標記-整理進行空間優(yōu)化;
3. 采用優(yōu)化-增量標記與惰性清理進行效率優(yōu)化;

標記-清除 與 標記-整理 算法

scavenge只復制活著的對象,而標記-清除只清除死了的對象。
活對象在新生代中只占較少部分,死對象在老生代中只占較少部分,這就是兩種回收方式都能高效處理的原因。

缺點
內(nèi)存碎片太多。如果出現(xiàn)需要分配一個大內(nèi)存的情況,由于剩余的碎片空間不足以完成此次分配,就會提前觸發(fā)垃圾回收,而這次回收是不必要的。

-> 標記-整理算法 標記完存活對象后,將存活對象向內(nèi)存空間的一端移動,移動完成后,清除掉邊界外的所有內(nèi)存

優(yōu)化-增量標記與惰性清理

增量標記

如果有很多對象,并且我們試圖一次遍歷并標記整個對象集,那么可能會花費一些時間,并在執(zhí)行中會有一定的延遲。因此,引擎試圖將垃圾回收分解為多個部分。然后,各個部分分別執(zhí)行。

V8對老生代垃圾回收器進行了優(yōu)化,從全停頓標記切換到增量標記。
將一次垃圾回收變成一小段一小段GC垃圾回收
JS中的垃圾回收機制怎么理解
如果采用非黑即白(存活和死亡)的標記策略,那在垃圾回收器執(zhí)行了一段增量回收后,暫停后啟用主線程去執(zhí)行了應用程序中的一段 JavaScript 代碼,隨后當垃圾回收器再次被啟動,這時候內(nèi)存中黑白色都有,我們無法得知下一步走到哪里了

惰性清理

增量標記完成后,惰性清理就開始了。當增量標記完成后,假如當前的可用內(nèi)存足以讓我們快速的執(zhí)行代碼,其實我們是沒必要立即清理內(nèi)存的,可以將清理過程稍微延遲一下,讓 JavaScript 腳本代碼先執(zhí)行,也無需一次性清理完所有非活動對象內(nèi)存,可以按需逐一進行清理直到所有的非活動對象內(nèi)存都清理完畢,后面再接著執(zhí)行增量標記

三色標記法 暫停和恢復

三色標記法的 mark 操作可以漸進執(zhí)行的而不需每次都掃描整個內(nèi)存空間,可以很好的配合增量回收進行暫?;謴偷囊恍┎僮?,從而減少 全停頓 的時間

  • 白色:未被標記的對象

  • 灰色:自身被標記,該對象的引用對象未被標記

  • 黑色:自身和該對象的引用對象(箭頭指的對象)都被標記

JS中的垃圾回收機制怎么理解
從一組根對象開始,先將這組根對象標記為灰色并推入到標記工作表中,當回收器從標記工作表中彈出對象并訪問它的引用對象時,將其自身由灰色轉(zhuǎn)變成黑色,并將自身的下一個引用對象轉(zhuǎn)為灰色

就這樣一直往下走,直到?jīng)]有可標記灰色的對象時,也就是無可達的對象了,那么剩下的所有白色對象都是無法到達的,即等待回收。

當前內(nèi)存中有沒有灰色節(jié)點來判斷整個標記是否完成,如沒有灰色節(jié)點,直接進入清理階段,如還有灰色標記,恢復時直接從灰色的節(jié)點開始繼續(xù)執(zhí)行就可以

寫屏障

一次完整的GC標記分塊暫停后,執(zhí)行任務程序,修改了對象的引用關(guān)系。
JS中的垃圾回收機制怎么理解
假設在第一次增量分段中全部將ABC標記為黑色,然后執(zhí)行JavaScript腳本,將B->D,開始執(zhí)行第二次增量分段。

新對象D是初始的白色,但是此時沒有灰色對象了,也就是全部標記完成需要開始清理了,D將會在清理階段被回收。這是不對的。
V8引入寫屏障機制,一旦有黑色對象引用白色對象,該機制就將引用的白色對象變?yōu)榛疑?/strong>。

并發(fā)回收
  • 并行回收會阻塞主線程

  • 增量標記增加了總暫停時間、降低應用程序吞吐量

主線程在執(zhí)行 JavaScript 的過程中,輔助線程能夠在后臺完成執(zhí)行垃圾回收的操作
JS中的垃圾回收機制怎么理解

以上就是關(guān)于“JS中的垃圾回收機制怎么理解”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

js
AI