看了這篇虛擬機 GC,可以跟面試官扯半天

GC的基礎知識

1.什麼是GC

GC 的全稱是Garbage Collection,垃圾回收。
垃圾回收的目的是什麼?
1:開發人員只管使用內存,無需關注內存的清除工作,使編程變得更簡單。
2:JAVA開發的系統更加健壯,避免因爲垃圾忘記回收導致內存溢出。

2 什麼是垃圾

  1. 方法執行完後,方法內定義的變量以及對象。
  2. for , each while 執行完當前輪循後, 循環裏定義的變量以及對象。
  3. if 執行完後,if內部定義的變量以及對象。
    PS:實例的變量對象有兩種,一種存在堆裏,一種存在棧裏。 這裏說的對象必須是存在堆裏的。存在棧的對象無需回收。

2.如何定位垃圾

  1. 引用計數(ReferenceCount)
    在 Java 中,引用和對象是有關聯的。如果要操作對象則必須用引用進行。因此,很顯然一個簡單的辦法是通過引用計數來判斷一個對象是否可以回收。簡單說,即一個對象如果沒有任何與之關聯的引用,即他們的引用計數都不爲 0,則說明對象不太可能再被用到,那麼這個對象就是可回收 對象。

  2. 根可達算法(RootSearching)
    爲了解決引用計數法的循環引用問題,Java 使用了可達性分析的方法。通過一系列的“GC roots” 對象作爲起點搜索。如果在“GCroots”和一個對象之間沒有可達路徑,則稱該對象是不可達的。要注意的是,不可達對象不等價於可回收對象,不可達對象變爲可回收對象至少要經過兩次標記過程。兩次標記後仍然是可回收對象,則將面臨回收
    GCroots包括:

    1. 虛擬機棧(棧幀中的局部變量區,也叫做局部變量表)中引用的對象
    2. 方法區中的類靜態屬性引用的對象
    3. 方法區中常量引用的對象
    4. 本地方法棧中JNI(Native方法)引用的對象

3.常見的垃圾回收算法

1): 標記清除(mark sweep)

首先,要對需要回收的對象進行標記,然後要對這些被標記的對象進行收集。如下圖所示
在這裏插入圖片描述

優點
1、算法簡單
缺點
​ 1、碎片嚴重。清除需要被清理的對象後剩下的內存都是破碎的,如果要創建大對象,可能會因爲找不到足夠的內存而再次觸發垃圾收集。
​ 2、效率低。標記和清除的效率相對於其他算法來說都不高,標記的原理就是從GC Roots往下遍歷,能被遍歷到的對象就是存活對象,剩下不能被遍歷到的對象就是需要被標記清除的。而清除時,是根據是否被標記,然後一個一個清除未被標記的。。這個效率就比較低了(遍歷了兩次才執行清除)。

2:拷貝算法 (copying) - 沒有碎片,浪費空間

大致原理,把內存分爲兩塊,分別命名爲A、B,A用於創建對象,B則是空閒內存(暫時不存放任何對象),當要進行垃圾回收時,把A中能被GC roots關聯到的對象(存活對象)全部複製到B中,然後把A中的所有內存空閒都清理掉。 如下圖所示。輪循重複以上步驟清除BABABA。
複製算法適用於年輕代。有統計得出,年輕代的內存95%都是朝生夕滅的,只有5%的內存是存活的。
在這裏插入圖片描述

優點
1、沒有碎片。內存總有一部分是完整的一塊,不會出現破碎內存的情況。
​ 2、高效。一般情況下,存活對象只佔所有對象中的很少一部分,百分之九十以上的對象都是要被清理掉的,所以複製存活對象到另一塊內存中所操作的對象數量就比較少,這樣的話,自然而然效率就高了。像標記-清除算法,是先要標記出所有不能存活的對象纔行,意味着要對大多數對象進行操作。
缺點
1、浪費內存。需要提供兩塊內存,一用一備 。

3:標記壓縮(mark compact)

標記-壓縮算法,那麼它也分爲兩個階段。先標記(mark),再壓縮(compact)。如下圖所示。 其中標記階段跟標記-清除算法中的標記階段是一樣的。而對於壓縮階段,它的工作就是移動所有的可達對象到堆內存的同一個區域中,使他們緊湊的排列在一起,從而將所有非可達對象釋放出來的空閒內存都集中在一起,通過這樣的方式來達到減少內存碎片的目的。
在這裏插入圖片描述

優點
​ 沒有碎片
缺點
效率偏低(兩遍掃描,標記與壓縮)

4:分代清理

1.8之前java虛擬機都是使用分代回收,如下圖所示。
在這裏插入圖片描述

1、年輕代EDEN,使用拷算法。年輕代的回收也叫Young GC,YGC頻繁執行清除。
a) 據統計得出,新創建的對象95%都是朝生夕滅的。第一輪的GC,只有5%的對象能存活下來。所以
新生代內存按照8:1:1的比例分爲一個Eden區和兩個survivor(survivor0,survivor1)區。
b) 第一輪GC,把Eden區存活對象複製到survivor0區
c) 第二輪GC,把Eden區存活對象+survivor0存活對象複製到survivor1區。
d) 第三輪GC,把Eden區存活對象+survivor1存活對象複製到survivor0區。
e) 輪循重複c,d。
2、老年代發生的GC也叫做Full GC,Full GC相對低頻率執行,Full GC主要使用 標記清除法。
a) 在年輕代中經歷了N次垃圾回收後仍然存活的對象,就會被放到年老代中。因此,可以認爲年老代中存放的都是一些生命週期較長的對象。
b) 內存比新生代也大很多(大概比例是1:2),當老年代內存滿時觸發Full GC,Full GC發生頻率比較低,老年代對象存活時間比較長,存活率標記高。

回收器

目前比較流行的垃圾收集器有七種。如下圖所示。
在這裏插入圖片描述
根據分區回收可以分爲:

1:年輕代:Serial, ParNew,Parallel Scavenge 。
2:老年代:CMS,Serial Old, Parallet Old用於老年代回收。
3:不分代:G1。

Serial: 單線程,使用拷貝算法。GC過程STW。
PartNew:多線程,使用拷貝算法,GC過程STW。實際上就是Serial的多線程版本。
Parallel Scavenge:多線程,使用拷貝算法,GC過過程STW。跟ParNew幾乎一樣,那它有什麼特別之處?

1:實際上ParNew配合老年代回收器是CMS,Serialold,而Parallel Scavenge配合的是Serial Old、Parallel Old。
2:ParNew關注的是儘可能的縮短GC的時間(STW時間),而Parallel Scavenge 更關注吞吐量。
PS :即 吞吐量= 運行 用戶 代碼 時間/( 運行 用戶 代碼 時間+ 垃圾 收集 時間), 虛擬 機 總共 運行 了 100 分鐘, 其中 垃圾 收集 花掉 1 分鐘, 那 吞吐量 就是 99%。

Serial Old: Serial 老年代版本。
Parallel Old: Parallel Scavenge老年代版本。
CMS: 是垃圾回收器的一個重要里程碑。目標是最大程度減少GC時STW時間。比其它回收器都複雜一些。它包括以下流程:初始標記,併發標記,重新標記,併發清除。如下圖所示。其中:

初始標記:STW,只找出根關聯的對象。STW時間很短。
併發標記:非STW,標記出垃圾。時間長,併發進行。。
重新標記:STW,再次確認已標的垃圾。
併發清除:非STW,清除垃圾。
在這裏插入圖片描述

G1:CMS的升級方案。具有以下特點:

並行與併發:充份利用多CPU的優勢,縮短STW時間。
分代收集:G1不需要與其它回收器配合,G1能分別處理年輕代與老年代。
可預測的停頓:能讓使用者明確指定在一個長度爲M毫秒的時間片段內,消耗在垃圾收集上的時間 不得超過N毫秒。
G1回收的流程與CMS差不多。如下圖所示
在這裏插入圖片描述

本人能力有限,如有錯誤請指出。
參考文獻:
周志明. 深入理解Java虛擬機:JVM高級特性與最佳實踐(第2版)
馬老師視屏。
https://www.cnblogs.com/sunniest/p/4575144.html
https://www.jianshu.com/p/698eb5e1ccb9

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章