JVM學習筆記(4)---垃圾收集器
哪些記憶體需要回收?
垃圾收集(Garbage Collection,GC),即常說的GC。
儘管目前“自動化”時代,記憶體由JVM自動回收,但需要了解其回收機制。當出現記憶體溢位、洩漏問題時方便排查,當垃圾收整合為系統達到更高併發量的瓶頸時,方便監控調節。
由於程式計數器、虛擬機器棧、本地方法棧隨執行緒生滅,且每個棧幀分配多少記憶體都是在類結構確定下來就已知,所以這幾個區域的記憶體分配和回收都有確定性。
而堆和方法區的記憶體分配是 動態 的,這裡所討論的GC即指 堆和方法區 的記憶體。
什麼時候回收?
記憶體的回收時機主要在於確定 物件是否還透過任何途徑被使用。
引用計數演算法(已經淘汰的演算法)
引用計數演算法是給每個物件新增一個引用計數器,每當一個地方引用它,計數器就加一;引用失效時,計數器就減一。
其特點是:演算法很簡單,判定效率高。但它不能解決相互引用的問題。
看如下示例程式碼:
public class ReferenceCountingGC { public Object instance = null; //這個成員屬性單純用於記憶體佔用,方便檢視是否回收 private byte[] bigSize = new byte[2*1024*1024]; public static void testGC(){ ReferenceCountingGC objA = new ReferenceCountingGC(); ReferenceCountingGC objB = new ReferenceCountingGC(); objA.instance = objB; objB.instance = objA; //清除引用 objA = null; objB = null; //GC 觀察objA與objB能否被回收 System.gc(); } public static void main(String[] args) { testGC(); } }
物件ObjA與ObjB互相引用,但再無其他引用。如果採用引用計數演算法,GC就無法回收他們。
主流的JVM中,沒有采用引用計數法,就是因為它無法解決物件間迴圈引用的問題。
執行上段程式碼,我們可以看到記憶體 4328k->644k 的變化,說明對ObjA和ObjB的記憶體進行了回收,也說明Java虛擬機器中沒有采用引用計數演算法。
執行結果
可達性分析演算法
主流商用程式語言(Java,C#等)中,都是透過 可達性分析(Rechability Analysis) 判斷物件存活。
可達性分析
可達性分析是透過一系列的"GC Roots"作為起始點,向下開始搜尋,所經過的路徑稱為引用鏈(Reference Chain),當一個物件到GC Roots沒有任何鏈相連,則物件不可用。
Java中,可作為GC Roots的物件包括以下幾種:
虛擬機器棧中引用的物件 (棧幀中的區域性變數表)
本地方法棧中JNI引用的物件 (JNI即Native方法)
方法區中靜態屬性引用的物件 (static)
方法區中常量引用的物件 (final)
物件引用
判斷物件的存活,無論是引用計數法計算數量,還是可達性分析法判斷引用的可達性,都與 引用 有關。
引用可分為 4 類:
強引用(Strong Reference):形如 Object obj = new Object(),只要引用在,GC不回收物件。
軟引用(SoftReference):記憶體溢位前,會進行二次回收,適合做快取
弱引用(WeakReference):下一次GC前,會直接進行回收
虛引用(PhantomRefence):僅用於物件回收時傳送系統通知
強引用
強引用的物件,不會被GC回收;刪除強引用後,GC才會回收。
示例程式碼如下:
/** * 強引用:GC不會回收物件 */public class StrongRef { public static void main(String[] args) throws InterruptedException { Referred strong = new Referred(); System.gc(); Thread.sleep(2000); //刪去引用 strong = null; System.out.println("刪除強引用後"); System.gc(); Thread.sleep(2000); } static class Referred { @Override protected void finalize() throws Throwable { System.out.println("GC時引用物件被收集"); } } }
finalize()函式:如果一個物件覆蓋了finalize()函式,則在物件被回收時,finalize()方法會被GC收集器觸發。每個物件的finalize()函式只會被系統呼叫一次。
執行結果如下:
刪除強引用後
GC時引用物件被收集
當強引用存在時,GC時物件沒被回收;當強引用被刪除,GC時物件被回收。
軟引用
軟引用的物件,在記憶體溢位前,會進行二次回收,這種特性非常適合做快取。
示例程式碼如下:
/** * VM args: -Xmx100m -Xms100m * */public class SoftRef { public static void main(String[] args) throws InterruptedException { SoftReference<Referred> soft = new SoftReference<Referred>(new Referred()); System.gc(); Thread.sleep(2000); System.out.println("開始堆佔用"); try { List<SoftRef> heap = new ArrayList<>(); while (true) { heap.add(new SoftRef()); } } catch (OutOfMemoryError e) { // 軟引用物件應該在這個之前被收集 System.out.println("記憶體溢位"); } } static class Referred { @Override protected void finalize() throws Throwable { System.out.println("GC時引用物件被收集"); } } }
作者:weberweber
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/818/viewspace-2818122/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【JVM學習筆記】垃圾收集器與記憶體分配策略JVM筆記記憶體
- java學習筆記-4 JVM垃圾回收(GC)Java筆記JVMGC
- JVM筆記(1.2)垃圾收集器和記憶體分配策略JVM筆記記憶體
- 【Java學習筆記】垃圾收集器和記憶體分配策略Java筆記記憶體
- 垃圾收集器學習
- JVM——垃圾收集器與記憶體分配JVM記憶體
- JVM垃圾收集器(八)JVM
- JVM調優:HotSpot JVM垃圾收集器JVMHotSpot
- JVM 垃圾收集器與記憶體分配策略JVM記憶體
- JVM垃圾收集器總結JVM
- JVM垃圾收集器專題JVM
- JVM 經典垃圾收集器JVM
- JVM學習筆記JVM筆記
- JVM(3)-垃圾收集器與記憶體分配策略JVM記憶體
- JVM-垃圾收集器與記憶體分配策略JVM記憶體
- 記一次jvm調優及垃圾收集器JVM
- JVM(五)-垃圾收集器入門JVM
- JVM學習筆記——初識JVMJVM筆記
- JVM核心學習筆記JVM筆記
- JVM 學習筆記(五)JVM筆記
- 今日學習JVM筆記JVM筆記
- JVM學習筆記-01JVM筆記
- 物件回收判定與垃圾回收演算法-JVM學習筆記(1)物件演算法JVM筆記
- 深入理解 JVM 之 垃圾收集器JVM
- 【JVM從小白學成大佬】5.垃圾收集器及記憶體分配策略JVM記憶體
- 深入理解JVM,7種垃圾收集器JVM
- JVM學習筆記之棧區JVM筆記
- JVM垃圾收集器基準報告 – Ionuț BaloșinJVM
- jvm系列(三)GC演算法 垃圾收集器JVMGC演算法
- 【JVM進階之路】七:垃圾收集器盤點JVM
- JVM 低延遲垃圾收集器 Shenandoah 和 ZGCJVMNaNGC
- 深入理解JVM記憶體回收機制(不包含垃圾收集器)JVM記憶體
- JVM虛擬機器-垃圾回收機制與垃圾收集器概述JVM虛擬機
- ☕[JVM技術指南](4)垃圾回收子系統(Garbage Collection System)之G1垃圾收集器SATBJVM
- swift學習筆記《4》Swift筆記
- python學習筆記4Python筆記
- Java學習筆記4Java筆記
- vue學習筆記4Vue筆記