垃圾對象判斷與回收

瞭解GC如何進行垃圾回收,也就是垃圾回收器如何工做,咱們首先要了解這幾個前置知識.如何判斷一個對象是不是垃圾對象,方法區中加載的類元信息如何判斷是無用類,垃圾回收算法,對象的最終標記.java

如何判斷一個對象是不是垃圾對象

引用記數法

顧名思義,這個方法其實就是判斷對象的引用數量來判斷這個對象是不是垃圾對象.給對象添加引用計數器,每多一個引用則引用數量+1,每少一個引用則引用數量-1.當此對象引用數量爲零,則對象爲垃圾對象.這種方式實現簡單且高效,可是這種方式存在着一種問題,也就是對象的循環依賴.假設如今有兩個對象,他們互相引用值爲null,且不存在其餘對象對其引用也不存在這兩個對象的使用,那麼這時這兩個對象應該就是垃圾對象,可是因爲他們互相引用,因此沒法被回收.算法

可達性分析算法

咱們仍是根據名字推測他的意思,可達性即這個對象能夠到達,對可達性進行分析來判斷對象是否存在引用,若是對象可達則不能回收,若是不可達則將對象標記爲垃圾對象等待回收,這也是主流虛擬機採用的方式,那麼這個可達性是什麼呢,要了解這個概念,咱們首先須要瞭解GC Roots根節點.3d

GC Roots根

咱們都知道java是單根結構,能夠根據一個Object根發展出一顆依賴樹來.那麼這個GC Roots根節點其實也有着殊途同歸之妙.他一樣的能夠以GC Root做爲根節點向下發展,發展出一顆依賴樹,經過這個GC Root向下探尋,能夠探尋到的對象咱們就稱其爲可達的.值得注意的一點是GC Root能夠有多個.cdn

GC Roots根是什麼

GC Roots有不少種類型,常見的好比說棧幀裏的本地變量(指向堆內存的對象),靜態變量等等對象

無用類

無用類(並不是學名)須要符合如下幾個條件blog

  • 這個類的全部引用已經消失(被回收)
  • 這個類的class信息被回收(不能經過反射建立此對象的實例)
  • 這個類的類加載器被回收

垃圾對象標記

垃圾對象的標記實際上是分爲兩個階段的,主要是看這個對象是否重寫了Object類的finalize()方法.內存

經過可達性分析咱們能夠對垃圾對象進行標記.可是對象實際上是有一個二次標記的過程的,重寫finalize()方法能夠進行第二次標記,若是對象沒有重寫這個方法則直接視爲垃圾對象.這一些執行第二次標記的對象,會執行這個方法內的代碼,若是在這個方法中把原本應該是垃圾對象的對象從新引用,好比設置一個成員變量並將這個實例賦給這個變量.那麼這個對象就不會被視爲垃圾對象,若是沒有對其進行從新引用則此對象視爲垃圾對象.虛擬機

垃圾回收算法

垃圾回收算法主要分爲四種it

標記-清除算法

這個算法分爲兩個部分,"標記","清除".io

標記即上述內容,經過可達性分析算法,不可達對象標記,二次標記中沒有自救的對象.

清除就是進行消除工做

這個算法具備兩個問題,效率問題與空間問題.

  • 效率問題:因爲垃圾對象存在不連續又沒有引用,因此標記的過程很耗時
  • 空間問題:這種清除算法會形成一些微小的內存碎片,從而形成內存的損失.

內存碎片就是佔用空間小無法放下其餘對象的的小內存空間.

標記-複製算法

這個算法將一塊內存區域分爲徹底相等的兩塊,這兩塊只能使用一塊,另外一塊作什麼用呢,用於垃圾清除後的空間整理.進行垃圾清除時,他會把當前這一半的全部存活對象依次移入到另外一半內存中去,移入完成後在對這一塊內存進行總體回收.因爲每次清理對象實際都存在一個整理的過程,因此這種算法不會產生垃圾碎片問題,又由於他是保留有用的對象,直接所有回收一塊內存空間,速度天然也比標記-清除算法快不少.

標記-整理算法

標記過程都相同,整理首先是將存活對象向前移動,將全部存活對象移到前面去,那麼此時會產生一個內存分界點,分界點一端所有都是有用對象,另外一端所有都是垃圾對象,這時候只須要對分界點的一端進行總體清理就能夠了.這個算法一樣不會產生垃圾碎片,效率也不低.

分代收集算法

分代收集算法並非像前三種算法那樣作一個清除的步驟,他只不過是將堆內存分爲了年輕代老年代,這樣咱們就能夠經過不一樣的策略針對不一樣的區採起不一樣的垃圾收集算法.

相關文章
相關標籤/搜索