引言
首先我們來介紹垃圾收集的概念,什么是垃圾收集?
? ? ? ? 垃圾收集?(Garbage Collection,GC),顧名思義就是釋放垃圾占用的空間,防止內存爆掉。有效的使用可以使用的內存,對內存堆中已經死亡的或者長時間沒有使用的對象進行清除和回收。
垃圾收集需要完成的三件事情:
? ? ? ? 哪些是垃圾?
? ? ? ? 怎么樣回收?
? ? ? ? 什么時間回收?
? ? ? ? 既然JVM要進行垃圾收集,首先就要判定哪些是垃圾?
?1. 哪些是垃圾
????????我們要判定哪些對象還“存活”著,哪些已經“死去”,有兩種算法:引用計數法和可達性分析。
1.1?腦門刻字法- 引用計數法
?思路:
????????在對象中添加一個引用計數器,通過計數器的加一減一操作,引用就加一,失效就減一。為零就回收。
????????引用計數算法看似很美好,但實際上它存在一個很大的問題,那就是無法解決循環依賴的問題。
public static void testGC() {
ReferenceCountingGC objA = new ReferenceCountingGC();
ReferenceCountingGC objB = new ReferenceCountingGC();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB = null;
// 假設在這行發生GC,objA和objB是否能被回收?
System.gc();
}
????????如果a和b相互引用,然后將這兩個對象的引用設置為 null,理論上它們會在接下來被垃圾回收器回收。但由于它們相互引用著對方,導致它們的引用計數永遠都不會為 0,通過引用計數算法,也就永遠無法通知 GC 收集器回收它們。
1.2?平地長樹法-可達性分析
思路:? ? ?
????????大白話就是:只要與GC Roots根對象關聯上,就不回收。
? ? ? ? 正式的話就是:通過 GC Roots 作為起點,然后向下搜索,搜索走過的路徑被稱為 Reference Chain(引用鏈),當一個對象到 GC Roots 之間沒有任何引用相連時,即從 GC Roots 到該對象節點不可達,則證明該對象是需要垃圾收集的。
????????所謂的 GC Roots,就是一組必須活躍的引用,不是對象,它們是程序運行時的起點,是一切引用鏈的源頭。在 Java 中,GC Roots 包括以下幾種:
- 虛擬機棧中的引用(方法的參數、局部變量等)
- 本地方法棧中 JNI (Java Native Interface)的引用
- 類靜態變量
- 運行時常量池中的常量(String 或 Class 類型)
2. 怎么樣回收
2.1 分代假說
分代收集理論
????????比如:有一堆2分鐘就要被清理的和一堆兩個小時的被清理的。分成兩堆
????????強分代假說:活得越久的,就越傾向于活下去 老年代 占2
????????弱分代假說:大部分朝生夕滅。 新生代 占1
????????跨代引用假說: 僅占極少數 (死的賊快的早死了,死的慢的就直接老年代了。)? ?
? ? ? ? ? ? ? ? 實現:在新生代建立一個全局的數據結構,這個結構把老年代劃分成若干個小塊,標識出老年代的哪一塊內存會存在跨代引用。包含了跨代引用小塊內存的對象會被加入GCRoots。
2.2 收集算法
1》標記清除
????????標記出要被回收的對象,標記完成后回收這些標記的對象。或者標記出存活的對象,回收未被標記的。
????????優勢:實現簡單
????????劣勢:①產生空間碎片問題
??????????????????②stop the world(在打標記的過程中,不能有新的對象產生。或者新的對象不打標記)
解決空間碎片化:
????????標記復制
2》標記復制
????????把內存劃分為容量相同的兩塊,每次只使用其中的一塊。當這一塊內存滿了,就將還存活的對象復制到另外一塊上,把原來滿的那塊內存清理掉。
????????好處:沒有空間碎片,實現簡單高效
????????壞處:收集效率不高的時候,使用這個算法不合適
???????????????????僅適用于收集效率高,朝生夕死合適
? ? ? ? ? ? ? ? ? ?只有一半的有效空間,另一半只能等著
????????優化:把整個新生代劃分成三部分
3》標記整理
????????適用于老年代。標記出要被回收的對象或者存活的對象,將所有存活的對象都向內存空間一端移動,然后清理掉邊界以外的內存。
????????好處:整理完后,沒有空間碎片
????????壞處:需要移動對象
Stop?The? World
????????"Stop The World"是 Java 垃圾收集中的一個重要概念。在垃圾收集過程中,JVM 會暫停所有的用戶線程,這種暫停被稱為"Stop The World"事件。
????????這么做的主要原因是為了防止在垃圾收集過程中,用戶線程修改了堆中的對象,導致垃圾收集器無法準確地收集垃圾。
????????值得注意的是,"Stop The World"事件會對 Java 應用的性能產生影響。如果停頓時間過長,就會導致應用的響應時間變長,對于對實時性要求較高的應用,如交易系統、游戲服務器等,這種情況是不能接受的。
????????因此,在選擇和調優垃圾收集器時,需要考慮其停頓時間。Java 中的一些垃圾收集器,如 G1 和 ZGC,都會盡可能地減少了"Stop The World"的時間,通過并發的垃圾收集,提高應用的響應性能。
????????總的來說,"Stop The World"是 Java 垃圾收集中必須面對的一個挑戰,其目標是在保證內存的有效利用和應用的響應性能之間找到一個平衡。