但是如果存在循環引用的情況,循環引用鏈上的對象的計數都無法變為0,所以這種情況是無法回收的
優點:
缺點:
標記清除(Mark-Sweep)算法依賴於對所有存活對象進行壹次全局遍歷來確定哪些對象可以回收,遍歷的過程從根出發,找到所有可達對象,除此之外,其它不可達的對象就是垃圾對象,可被回收。
整個過程分為兩個階段:
執行過程如圖:
內存布局變化如圖:
可以看到清除垃圾對象之後的內存是不連續的
優點:
缺點:
由於標記清除算法有壹個比較大的問題,就是導致內存碎片,為了解決這個問題,在清除不可達對象之前,先做壹下整理,使得活動對象占據的內存是連續的,這就是標記整理算法,是對標記清除算法的增強。標記整理階段內存變化如下:
可以看到清除垃圾對象之後的內存是連續的
分代回收算法並不是指特定的某壹種GC回收算法,而是多種GC回收算法的組合算法,包括:
本文以V8引擎的垃圾回收機制進行講解。
首先分代回收算法會將內存對象分為 新生代 和 老生代 :
在分代的基礎上,新生代中的對象主要通過Scavenge算法進行垃圾回收。而在Scavenge的具體實現中,主要采用了Cheney算法。
Cheney算法是壹種采用復制的方式實現的垃圾回收算法。它將堆內存壹分為二,每壹部分空間稱為semispace。在這兩個semispace空間中,只有壹個處於使用中,另壹個處於閑置狀態。處於使用狀態的semispace空間稱為From空間,處於閑置狀態的空間稱為To空間。當我們分配對象時,先是在From空間中進行分配。當開始進行垃圾回收時,會檢查From空間中的存活對象,這些存活對象將被復制到To空間中,而非存活對象占用的空間將會被釋放。完成復制後,From空間和To空間的角色發生對換。
Scavenge的缺點是只能使用堆內存中的壹半,這是由劃分空間和復制機制所決定的。但Scavenge由於只復制存活的對象,並且對於生命周期短的場景存活對象只占少部分,所以它在時間效率上有優異的表現。
由於Scavenge是典型的犧牲空間換取時間的算法,所以無法大規模地應用到所有的垃圾回收中。但可以發現,Scavenge非常適合應用在新生代中,因為新生代中對象的生命周期較短,恰恰適合這個算法。
Scavenge算法的內存布局:
新生代GC流程如下:
對於老生代區域已經存在的對象主要是以標記清除方式為主,對於晉升過來的數據,先檢查是否有足夠空間,如果有則直接存儲,如果沒有足夠空間,則進行標記管理,整理碎片內存,然後再進行存儲
V8引擎實際上在進行垃圾回收的時候是增量進行的,把壹次回收過程分成了很多的子過程進行,這樣可以避免因為垃圾回收導致的卡頓
下壹篇: JS性能優化