垃圾回收機制

一、 引用計數

    引用計數算法是垃圾回收最先的算法,有其優點,也有其劣勢,可是如今已經不多有使用了。算法

原理:爲每一個對象添加一個計數器,表示對象的引用次數,每當建立一個新的引用指向該對象時其計數器就加1,每當指向該對象的引用失效時計數器就減1。當計數器的值爲0時就會被瀏覽器回收。瀏覽器

優勢:併發

可即刻回收垃圾:當計數器值爲0時,會立刻回收對象,提升內存使用效率
STW(Stop-The-World)短: 回收垃圾時,瀏覽器會中止響應其餘操做,引用計數不須要遍歷堆,有效減小STW時間

缺點:性能

計數器的增減操做頻繁
計數器須要佔用必定的內存
實現繁瑣,更新引用時很容易致使內存泄露。
循環引用沒法回收(最重要的缺點)

二、 標記清除

    現代瀏覽器使用最多的一種垃圾回收機制。優化

原理:從名字就能夠看出,該算法分爲兩個步驟:1.標記全部可訪問的對象;2.清除全部未被標記的對象。code

優勢:對象

算法實現簡單。

缺點:內存

碎片化:清楚後的空間是不連續的,不利於後面空間的分配。
分配速度慢:因爲空間碎片化,因此每次分配須要遍歷空閒鏈表。
STW(Stop-The-World)長:兩個階段均要遍歷整個堆。

優化:採用標記整理算法或標記壓縮算法進行內存整理,避免內存碎片化。效率

三、 GC優化策略 - 分代回收

    V8 實現了準確式 GC,採用了分代式垃圾回收機制,將內存(堆)按照8:2分爲老生代和新生代兩部分,其中新生代又按照1:1分爲了兩塊Survivor空間。原理

    一方面新生代中的對象可能是臨時對象,另外一方面新生代空間中有一半是空閒的,因此只分的兩成的空間。

    新生代 GC採用複製算法。在新生代空間中,內存空間分爲兩部分,分別爲 From 空間和 To 空間。在這兩個空間中,一定有一個空間是使用的,另外一個空間是空閒的。新分配的對象會被放入 From 空間中,當 From 空間被佔滿時,新生代 GC 就會啓動了。算法會檢查 From 空間中存活的對象並複製到 To 空間中,若是有失活的對象就會銷燬。當複製完成後將 From 空間和 To 空間互換,這樣 GC 就結束了。若是垃圾回收時,存活的對象太多,To 空間的對象佔比大小超過 25 %。在這種狀況下,爲了避免影響到內存分配,會將對象重新生代空間移到老生代空間中,就會出現有些對象提早進入老生代的狀況。

    當新生代中的對象經歷過一次 Scavenge 算法後,會將對象重新生代空間移到老生代空間中。

    老生代 GC採用標記清除算法和標記壓縮算法。老年代中主要存放存活時間較長的持久對象,這類對象數量較多。當老年代中的內存消耗超過必定限制時,會先啓動標記清除算法,清除對象後會形成堆內存出現碎片的狀況,當碎片超過必定限制後會啓動壓縮算法。在壓縮過程當中,將活的對象像一端移動,直到全部對象都移動完成而後清理掉不須要的內存。

    在 GC時,瀏覽器會中止響應其餘操做,而一次GC可能須要幾百毫秒才能完成。這就會致使一些性能上的問題。爲了解決這個問題,2011 年,V8 從 stop-the-world(STW) 標記切換到增量標誌。在增量標記期間,GC 將標記工做分解爲更小的模塊,可讓 JS 應用邏輯在模塊間隙執行一會,從而不至於讓應用出現停頓狀況。在 2018 年,GC 技術又有了一個重大突破,這項技術名爲併發標記。該技術可讓 GC 掃描和標記對象時,同時容許 JS 運行。

相關文章
相關標籤/搜索