引用計數算法是垃圾回收最先的算法,有其優點,也有其劣勢,可是如今已經不多有使用了。算法
原理:爲每一個對象添加一個計數器,表示對象的引用次數,每當建立一個新的引用指向該對象時其計數器就加1,每當指向該對象的引用失效時計數器就減1。當計數器的值爲0時就會被瀏覽器回收。瀏覽器
優勢:併發
可即刻回收垃圾:當計數器值爲0時,會立刻回收對象,提升內存使用效率 STW(Stop-The-World)短: 回收垃圾時,瀏覽器會中止響應其餘操做,引用計數不須要遍歷堆,有效減小STW時間
缺點:性能
計數器的增減操做頻繁 計數器須要佔用必定的內存 實現繁瑣,更新引用時很容易致使內存泄露。 循環引用沒法回收(最重要的缺點)
現代瀏覽器使用最多的一種垃圾回收機制。優化
原理:從名字就能夠看出,該算法分爲兩個步驟:1.標記全部可訪問的對象;2.清除全部未被標記的對象。code
優勢:對象
算法實現簡單。
缺點:內存
碎片化:清楚後的空間是不連續的,不利於後面空間的分配。 分配速度慢:因爲空間碎片化,因此每次分配須要遍歷空閒鏈表。 STW(Stop-The-World)長:兩個階段均要遍歷整個堆。
優化:採用標記整理算法或標記壓縮算法進行內存整理,避免內存碎片化。效率
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 運行。