一、垃圾回收算法
1、引用計數法
引用計數法的實現非常簡單,只需要為每個對象配備一個計數器即可。但是存在一個嚴重的問題就是不能解決循環應用的問題。因此在java的垃圾回收器中,沒有使用這種算法。
2、標記清除算法
標記清楚算法是現在垃圾回收算法的思想基礎。標記清除算法將垃圾回收分為兩個階段:標記和清除階段。
在標記階段,首先通過根節點,標記所有從根節點開始的可達對象。因此未被標記的對象就是未被引用的垃圾對象。然后在清除階段,清除未被標記的對象。標記清楚算法可能產生最大的問題就是空間碎片。
3、復制算法
與標記清除算法相比,復制算法是一種相對高效的回收方法。它的核心思想是:將原有的內存空間分為兩塊,每次只使用其中一塊,在垃圾回收時,將正在使用的內存塊中的存活對象復制到未使用的內存塊中,之后,清除正在使用的內存塊中的所有對象,交換兩個內存的角色,完成垃圾回收。
如果系統中的垃圾對象很多,復制算法需要復制的存活對象數量并不會太大。因此在真正需要垃圾回收的時刻,復制算法的效率是很高的。又由于對象是再垃圾回收過程中統一被復制到新的內存空間中,因此,可確?;厥蘸蟮膬却婵臻g是沒有碎片的。雖然有以上兩大優點,但是復制算法的代價缺點是將系統內存折半,因此,單純的復制算法也很難讓人接受。
在java的新生代串行垃圾回收器中,使用的復制算法思想。
在垃圾回收時,Eden空間的存活對象會被復制到未使用的survivor空間中(假設是to),正在使用的survivor空間(假設是from)中的年輕對象也會被復制to空間中(大對象或者老年對象直接回進入老年代,如果to空間已滿,則對象也會直接進入老年代)此時Eden空間和from空間中的剩余對象就是垃圾對象,可以直接清空,to空間則存放此次回收的存活對象。
4、標記-壓縮算法
復制算法的高效性是建立在存活對象少,垃圾對象多的前提下的。這種情況在年輕代經常發生,但是在老年代,更常見的情況大部分對象都是存活對象。如果依然使用復制算法,由于存活對象較多,復制的成本也將很高。因此,基于老年代垃圾回收的特性,需要使用新的算法。標記壓縮算法是一種老年代的回收算法,它在標記清除的算法的基礎上做了一些優化,標記壓縮算法也需要從根節點開始,對所有可達對象做一次標記。但之后,并不是清理未標記的對象,而是將所有的存活對象壓縮到內存的一端。之后,清理邊界的所有空間。這種方法即避免了碎片的產生,又不需要兩塊相同的內存空間,因此性價比較高。
5、增量算法
對大部分的垃圾回收算法而言,在垃圾回收的過程中,應用軟件將處于一種Stop the World的狀態。在Stop the World 的狀態下,應用程序的所有線程都會被掛起,暫停一切正常的工作,等待垃圾回收完成。如果垃圾回收時間很長,應用程序就會掛起很久,將會嚴重影響用戶體驗或者系統的穩定性。
增量算法的基本思想是,如果一次將所有的垃圾進行處理,需要造成系統的長時間停頓,那么久可以讓垃圾收集的線程和應用程序線程交替執行。每次垃圾收集只收集一小片區域,接著切換到應用線程??梢詼p少系統的停頓時間。但是,因為線程的切換和上下文轉換的消耗,會使得垃圾回收的成本上升,造成吞吐量的下降。
6、分代
以Hot Spot為例,新生代用復制算法,老年代用標記壓縮算法。
二、垃圾收集器的類型
按線程分,可以分為串行垃圾回收器和并行垃圾回收器。串行垃圾回收器一次只使用一個線程進行垃圾回收;并行垃圾回收器一次將開啟多個線程同時進行垃圾回收。在并行能力較強的CPU上使用并行垃圾回收器可以縮短GC的停頓時間。
按照工作模式分,可以分為并發式垃圾回收器和獨占式垃圾回收器。并發式垃圾回收器與應用程序線程交替工作,以盡可能的減少應用程序的停頓時間;獨占式垃圾回收器(Stop the World)一旦運行,就停止應用程序中的其他線程,直到垃圾回收過程完全結束。
按照碎片處理方式,可分為壓縮式垃圾回收和非壓縮式垃圾回收器。壓縮式垃圾回收器會在回收完成后,對存活的對象進行壓縮整理,消除回收后的碎片;非壓縮式的垃圾回收器,不進行這不操作。
按工作的內存區間,又可分為新生代垃圾回收器和老年代垃圾回收器。顧名思義,新生代垃圾回收器只在新生代工作;老年代垃圾回收器則工作在老年代。