JVM·垃圾收集器與內存分配策略之對象是否可被回收!
阿新 • • 發佈:2019-02-28
pri 計數 isalive 第一次 lis 不同的 protect live() null 1、判斷對象已經死去/不再被引用。
1.1、引用計數算法:給對象添加引用計數器,有個地方引用就+1,引用失效就-1。任何時刻,引用為0,即判斷對象死亡。
1.1.1、優點:實現簡單,效率高。
1.1.2、缺點:在主流的Java虛擬機中不被使用,因為很難解決對象之間相互循環引用的問題。
1.2、可達性分析算法(Java,C#,lisp):從一系列稱為“GC Roots”的對象作為起始點,從這些節點往下搜索,搜索走過的路徑稱為引用鏈,當沒有引用鏈可達到某對象時,認為該對象不可到達,即此對象沒有被有效引用。
1.2.1: 可做為GC Roots的對象:
虛擬機棧中引用的對象
方法區中類靜態屬性引用的對象
方法區中常量引用的對象
本地方法棧中JNI(Native方法)應用的對象
2、如何判斷是否要被回收
在Java中,采用可達性分析算法。即使判斷未不可達的對象,也不會立即宣告對象死亡。在此之前要經過至少兩次標記:
2.1、第一次標記和篩選:當第一次判斷該對象不可達(沒有與GC Roots相連的引用鏈)時,進行篩選:是否要執行finalize()方法。
2.2、第二次: 需要finalize()方法的對象會在一個低優先級的F-Queue中排隊執行finalize()。如果在finalize()方法中拯救自己,那麽就不會死。否則,被回收。
在finalize()方法中拯救自己:在改方法中重新連接上GC Roots(重新擁有連接GC Roots的引用)
2.3、總結:對象可以在被GC時自我拯救。這種拯救只有一次機會,因為GC只會調用一次對象的finalize()方法。
附自我拯救代碼:
** * Created by KEY on 2017/12/4. */ public class FinalizeEscapeGC { public static FinalizeEscapeGC SAVA_HOOK = null; public void isAlive(){ System.out.println("yes, I am still alive"); } @Override protected void finalize() throws Throwable{ super.finalize(); System.out.println("finalize method executed"); FinalizeEscapeGC.SAVA_HOOK = this; } public static void main(String[] args) throws Throwable{ SAVA_HOOK = new FinalizeEscapeGC(); //對象第一次拯救自己 SAVA_HOOK = null; System.gc(); //因為finalize優先級很低,所以等他0.5s Thread.sleep(500); if(SAVA_HOOK != null){ SAVA_HOOK.isAlive(); }else{ System.out.println("no,I am dead :("); } //重復以上代碼,看是否能第二次拯救自己 //對象第一次拯救自己 SAVA_HOOK = null; System.gc(); //因為finalize優先級很低,所以等他0.5s Thread.sleep(500); if(SAVA_HOOK != null){ SAVA_HOOK.isAlive(); }else{ System.out.println("no,I am dead :("); } } }
3、方法區的垃圾回收 說明:虛擬機規範對於方法區的實現並沒有要求是否回收,也沒有要求如何回收,甚至沒有要求具體的內存定義, 只需要滿足方法區規範即可。所以方法區的回收再不同的虛擬機有不同的實現 方法區的回收主要針對“廢棄常量”和“無用的類”。如何判斷是否是“無用的類” a.該類所有的實例都已經被回 b.加載該類的ClassLoader被回收 c.該類對應的java.lang.class對象沒有在任何地方被引用,無法再任何地方通過反射訪問該類的方法。
JVM·垃圾收集器與內存分配策略之對象是否可被回收!