日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

根可达算法的根_好屌好屌的「GC系列」JVM垃圾定位及垃圾回收算法浅析

發布時間:2025/3/11 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 根可达算法的根_好屌好屌的「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 小結

  • 沒有任何引用指向的對象是垃圾
  • 找到垃圾的算法有引用計數法(Reference Count)和根可達算法(Root Searching)
  • 引用計數法無法解決循環引用的問題
  • GC Roots:線程棧變量、靜態變量、常量池、JNI指針
  • 垃圾回收算法:標記清除(Mark Sweep)、拷貝(Copying)、標記壓縮(Mark Compact)
  • 標記清除算法容易產生內存碎片使內存空間不連續
  • 拷貝算法沒有內存碎片產生但是浪費空間
  • 標記壓縮算法效率雖然有點低但沒有內存碎片產生且不浪費內存空間

  • 作者:行百里er
    鏈接:https://juejin.im/post/6888847017846669320
    來源:掘金
    著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

    總結

    以上是生活随笔為你收集整理的根可达算法的根_好屌好屌的「GC系列」JVM垃圾定位及垃圾回收算法浅析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。