JVM之二週目

轉自:JVM完整深入解析

今天我們來看看JVM的垃圾回收機制(GC)

我們可以從以下三個方面來學習GC:

  1. 哪些對象可以被回收
  2. 何時回收GC
  3. 採用什麼方式回收

GC (Garbage Collection)的基本原理:將內存中不再被使用的對象進行回收,GC中用於回收的方法稱爲收集器,由於GC需要消耗一些資源和時間,Java在對對象的生命週期特徵進行分析後,按照新生代、舊生代的方式來對對象進行收集,以儘可能的縮短GC對應用造成的暫停

一、 判斷對象是否要回收的方法:可達性分析法

1、 可達性分析法:通過一系列“GC Roots”對象作爲起點進行搜索,如果在“GC Roots”和一個對象之間沒有可達路徑,則稱該對象是不可達的。不可達對象不一定會成爲可回收對象。進入DEAD狀態的線程還可以恢復,GC不會回收它的內存。(把一些對象當做root對象,JVM認爲root對象是不可回收的,並且root對象引用的對象也是不可回收的)
2、 以下對象會被認爲是root對象:

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

3、 對象被判定可被回收,需要經歷兩個階段:

  1.  第一個階段是可達性分析,分析該對象是否可達
  2.  第二個階段是當對象沒有重寫finalize()方法或者finalize()方法已經被調用過,虛擬機認爲該對象不可以被救活,因此回收該對象。(finalize()方法在垃圾回收中的作用是,給該對象一次救活的機會)

4、 方法區中的垃圾回收:

  1.  常量池中一些常量、符號引用沒有被引用,則會被清理出常量池
  2. 無用的類:被判定爲無用的類,會被清理出方法區。判定方法如下:
  •  該類的所有實例被回收
  •  加載該類的ClassLoader被回收
  • 該類的Class對象沒有被引用

5、 finalize():

  1. GC垃圾回收要回收一個對象的時候,調用該對象的finalize()方法。然後在下一次垃圾回收的時候,纔去回收這個對象的內存。
  2.  可以在該方法裏面,指定一些對象在釋放前必須執行的操作。

二、 發現虛擬機頻繁full GC時應該怎麼辦:

(full GC指的是清理整個堆空間,包括年輕代和永久代)

  1.  首先用命令查看觸發GC的原因是什麼 jstat –gccause 進程id
  2.  如果是System.gc(),則看下代碼哪裏調用了這個方法
  3.  如果是heap inspection(內存檢查),可能是哪裏執行jmap –histo[:live]命令
  4.  如果是GC locker,可能是程序依賴的JNI庫的原因

三、常見的垃圾回收算法

1、Mark-Sweep(標記-清除算法):

  • 思想:標記清除算法分爲兩個階段,標記階段和清除階段。標記階段任務是標記出所有需要回收的對象,清除階段就是清除被標記對象的空間。
  • 優缺點:實現簡單,容易產生內存碎片

2、Copying(複製清除算法):

  • 思想:將可用內存劃分爲大小相等的兩塊,每次只使用其中的一塊。當進行垃圾回收的時候了,把其中存活對象全部複製到另外一塊中,然後把已使用的內存空間一次清空掉。
  • 優缺點:不容易產生內存碎片;可用內存空間少;存活對象多的話,效率低下。

3、Mark-Compact(標記-整理算法):

  • 思想:先標記存活對象,然後把存活對象向一邊移動,然後清理掉端邊界以外的內存。
  • 優缺點:不容易產生內存碎片;內存利用率高;存活對象多並且分散的時候,移動次數多,效率低下

4、分代收集算法:(目前大部分JVM的垃圾收集器所採用的算法):

思想:把堆分成新生代和老年代。(永久代指的是方法區)

  1.  因爲新生代每次垃圾回收都要回收大部分對象,所以新生代採用Copying算法。新生代裏面分成一份較大的Eden空間和兩份較小的Survivor空間。每次只使用Eden和其中一塊Survivor空間,然後垃圾回收的時候,把存活對象放到未使用的Survivor(劃分出from、to)空間中,清空Eden和剛纔使用過的Survivor空間。
  2.  由於老年代每次只回收少量的對象,因此採用mark-compact算法。
  3.  在堆區外有一個永久代。對永久代的回收主要是無效的類和常量

5、GC使用時對程序的影響? 
垃圾回收會影響程序的性能,Java虛擬機必須要追蹤運行程序中的有用對象,然後釋放沒用對象,這個過程消耗處理器時間
6、幾種不同的垃圾回收類型:

(1)Minor GC:從年輕代(包括Eden、Survivor區)回收內存。

A、當JVM無法爲一個新的對象分配內存的時候,越容易觸發Minor GC。所以分配率越高,內存越來越少,越頻繁執行Minor GC
B、執行Minor GC操作的時候,不會影響到永久代(Tenured)。從永久代到年輕代的引用,被當成GC Roots,從年輕代到老年代的引用在標記階段直接被忽略掉。

(2)Major GC:清理整個老年代,當eden區內存不足時觸發。

(3)Full GC:清理整個堆空間,包括年輕代和老年代。當老年代內存不足時觸發

 

 

 

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