標籤:pos 條件 集合 div except rgs 概念 owa abc
博文重點:
學習目標:哪些記憶體需要回收
什麼時候回收
如何回收
在基於概念討論的模型中,主要對Java堆和方法區進行討論。
why?:一個介面中的多個實作類別需要的記憶體可能不一樣,一個方法中的多個分支需要的記憶體也可能不一樣。只有在程式運行期間才能知道會建立哪些對象,這部分記憶體的分配和回收都是動態,gc關注的就是這一塊記憶體。
哪些記憶體需要回收:
判斷對象是否存活:
引用計數演算法:對象中添加一個引用計數器,有一個地方引用它則計數器加1,引用失效時,減1。引用為0的對象就是不可使用的。
優點:實現簡單,判定效率高。
缺點:無法解決對象之間的循環參考,見代碼。
1 public class ReferenceCountingGC { 2 public Object instance = null; 3 4 private static final int _1MB = 1024 * 1024; 5 6 private byte[] bigSize = new byte[2 * _1MB]; 7 8 public static void testGC() { 9 ReferenceCountingGC objA = new ReferenceCountingGC();10 ReferenceCountingGC objB = new ReferenceCountingGC();11 objA.instance = objB;12 objB.instance = objA;13 14 15 objA = null;16 objB = null;17 18 // 雖然引用計數都為1,但記憶體還是被回收了,說明採用的不是引用計數演算法19 System.gc();20 }21 22 public static void main(String[] args) {23 testGC();24 }25 } View Code
可達性分析演算法:思路,選擇一系列稱為"GC Roots"的對象作為起始點,從這些節點向下搜尋,走過的路就稱為引用鏈。如果一個對象無法通過引用鏈到達"GC roots",則證明該對象不可用,則可被回收。
可作為GC Roots的對象:虛擬機器棧中引用的對象,方法區類靜態屬性引用的對象,方法區中常量引用的對象,Nativa方法中引用的對象。 todo:理解gc roots
引用:
todo:各種應用情境
引用細化定義:當記憶體空間還足夠,則能保留在記憶體中。如果記憶體空間進行垃圾收集之後還是非常緊張,則拋棄這些對象。
基於這樣的需求,擴充了引用的概念。
強引用:只要強引用存在,就永遠不會被gc。eg. Object obj = new Object();
軟引用:記憶體充足時不會回收,不足時被回收。jvm將這個軟引用加入到與之關聯的引用隊列
弱引用:無論記憶體是否充足,都會進行回收。jvm將這個弱引用加入到與之關聯的引用隊列
虛引用:
對象的兩次標記:如果對象在進行第一次可達性分析之後,沒有到gc roots到引用鏈,則進行第一次標記。並進入第一次自救過程,如果該對象重寫了finalize()方法時 && finalize()方法沒有被虛擬機器調用過,則會執行finalize()方法進行自救過程,將該對象放入到一個F-Queue到隊列中,由虛擬機器自動建立的,低優先順序的Finalize線程去執行(但是不保證會等待方法運行結束,為了效率考慮)。如果在finalize()方法中將該對象的引用賦值給了類變數或成員變數,重建立立起了可達關係,則在該第二次標記過程會被移出"即將回收"集合,自救成功,但要注意,這樣的自救只能執行一次。
1 public class FinalizeEscapeGC { 2 public static FinalizeEscapeGC SAVE_HOOK = null; 3 public void isAlive() { 4 System.out.println("yes , i am still alive"); 5 } 6 7 @Override 8 protected void finalize() throws Throwable { 9 System.out.println("finalize method excute!");10 FinalizeEscapeGC.SAVE_HOOK = this;11 }12 13 public static void main(String[] args) throws InterruptedException {14 SAVE_HOOK = new FinalizeEscapeGC();15 16 // 第一次拯救自己成功17 SAVE_HOOK = null;18 System.gc();19 20 Thread.sleep(500);21 if(SAVE_HOOK != null) {22 SAVE_HOOK.isAlive();23 } else {24 System.out.println("dead");25 }26 27 // 第二次拯救自己失敗,只能執行一次28 SAVE_HOOK = null;29 System.gc();30 31 Thread.sleep(500);32 if(SAVE_HOOK != null) {33 SAVE_HOOK.isAlive();34 } else {35 System.out.println("dead");36 }37 }38 }View Code
方法區(永久代)的回收:主要回收廢棄常量和無用類。
廢棄常量:eg:"abc"存在常量池中,但沒有其它地方引用這個常量,類,方法,欄位的符號引用也和這個類似。
無用類:該類所有執行個體已被回收
載入該類的ClassLoader已被回收
對應的Class對象沒有被引用,無法在其它地方通過反射訪問該類的方法。
滿足了這些條件的類可以被回收,是否進行回收,取決於我們對虛擬機器的參數設定情況。
使用情境:在大量使用反射,動態代理,CGLib等頻繁定義自ClassLoader的情境都需要虛擬機器具備類卸載的功能
深入理解java虛擬機器---垃圾收集器和分配策略-1