根可达算法的根_好屌好屌的「GC系列」JVM垃圾定位及垃圾回收算法浅析
0x01 什么是垃圾
很簡單,沒有引用指向的任何對象都叫做垃圾(garbage)。
什么是garbage
在某一內存空間中,Java程序制造了很多對象被引用,有的對象還引用別的對象,中途有對象不被需要了就沒有指向他的引用了,這些沒有引用指向的東西就是垃圾。
這些垃圾不需要自己回收,JVM中有類似于街道上那些勤勞的環衛工的人,在幫忙回收垃圾。
0x02 如何找到垃圾
那么,幫忙回收垃圾的人是如何找到垃圾的呢?JVM中一般有兩種算法:
- Reference Count 引用計數
- Root Searching 根可達算法
2.1 引用計數
引用計數法設定給對象中添加一個引用計數器,每當有一個地方引用它時,計數器值加1;當引用失效時,計數器值減1,引用數量為0的時候,則說明對象沒有被任何引用指向,,可以認定是“垃圾”對象。
引用計數法
但是引用計數法不能解決循環引用的問題,比如O1->O2->O3->O1,當沒有引用指向他們任何一個的時候,他們的reference count都是1,按照引用計數法,他們都不是垃圾。
而事實上,沒有任何引用指向O1、O2、O3這一坨了,他們都是垃圾。
JVM(看向O1):堅決不能容忍垃圾!
O1:看什么,我的引用計數為1,不是0,我不是垃圾。
JVM:不好意思,我不是針對你,我是說你們一坨都是垃圾!
引用計數法無法確定垃圾的情況
2.2 根可達算法
引用計數法不能解決循環引用的問題,可采用根可達算法(Root Searching)。
其算法思路就是通過一系列名為 GC Roots 的對象作為根,從根上開始向下搜索,搜索所走過的路徑稱為引用鏈(Reference Chain),當一個對象到 GC Roots 沒有任何引用鏈相連時,則證明此對象是不可用的。
那么哪些是 Roots 呢?
- 線程棧變量
Java程序從main方法開始執行,main方法會開啟一個線程,這個線程里有線程棧,里面有棧幀。
從main開始這個線程棧幀里面的這些個叫做根對象。
- 靜態變量
一個class被load到內存之后,馬上就對靜態變量進行初始化,所以靜態變量訪問到的對象也是根對象。
- 常量池
如果一個class能夠用到其他的class的對象,那么他就是根對象。
- JNI指針
本地方法用到本地的對象也是根對象。
總之,當一個程序起來之后馬上需要的對象叫做根對象。
0x03 常見的垃圾回收算法
垃圾找到了之后就要回收,那么JVM怎么進行垃圾回收呢?
如何進行垃圾清除,常用的算法有3種:
- Mark-Sweep 標記清除
- Coping 拷貝算法
- Mark-Compact 標記壓縮
3.1 標記清除
先標記垃圾,然后清除垃圾。通過該算法,先找到那些有用的對象,沒有用的并出來然后把它們清除掉。
從圖中可以看出,標記清除算法將垃圾標記并清除后,內存中原先不可用的內存變成了空閑的可用的,但是這些內存有些有些不連續了,也就是說產生了碎片。
再一個,如果存活的對象比較多,這種情況標記清除算法的執行效率比較高。相反執行效率就稍微低一點,因為需要兩遍掃描,第一次掃描找到那些有用的,第二次掃描把那些沒用的找出來清理掉。
3.2 拷貝算法
拷貝算法,就是把內存一分為二,比如A、B兩個區域,分開之后,把A區域中有用的拷貝到B區域,拷貝完成后,把A區域全部清除,下次再分配內存的時候先往B區域分配,如此往復。
1) 把內存一分為二,分為A、B兩個區域,分配內存先往A區域分配
2) 拷貝A區域中存活的有用的對象到B區域
拷貝完成的狀態:
3) 將A區域全部清除(內存全部釋放)
4) 之后再分配內存的時候往B區域分配
清除B之后再繼續往A區域分配,如此往復,拷貝來拷貝去。
以上過程就是拷貝算法。
該算法適用于存活對象較少的情況,只掃描一次,效率有所提高并且沒有產生內存碎片。需要注意的是,移動復制對象時須調整對象引用。
缺點也顯而易見,得準備兩份內存,浪費空間。
3.3 標記壓縮
對象分配到內存之后,需要回收的時候,先把沒有引用指向的對象標記為垃圾,然后把后面存活的對象拷貝到標記的那個地方,不僅如此,最后凡是有用的對象全部移到前面,無論這個內存是沒有使用,都壓縮整理到前面,最后剩下的大塊空間就全部清理出來了。
可以看到,標記壓縮進行回收垃圾之后,空間連續,沒有碎片。
我們分析一下該算法的實現思路,
1)通過GC Roots找到那些有用的不可回收的
2)把不可回收的有用對象往前移動
所以肯定需要掃描兩次內存,而且還要移動對象,第一次掃描先找游泳對象,第二次掃描移動對象。
移動的過程中,如果是多線程還要考慮線程同步,所以標記壓縮算法效率上要低一些。
該算法的優點在于對象分配不會產生內存減半,而且不會產生內存碎片。
0x04 小結
作者:行百里er
鏈接:https://juejin.im/post/6888847017846669320
來源:掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
總結
以上是生活随笔為你收集整理的根可达算法的根_好屌好屌的「GC系列」JVM垃圾定位及垃圾回收算法浅析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机程序的构造和解释 python_S
- 下一篇: java for each 原理_Jav