JVM 類的卸載

類的卸載:由JVM自帶的類加載器所加載的類,在JVM的生命週期中,始終不會被卸載。JVM自己會始終引用這些類加載器,而這些類加載器始終引用它們所加載的類的Class對象。因此說,這些Class對象始終是可觸及的。 spa

由用戶自定義的類加載器所加載的類是能夠被卸載的。
 
當類被加載,鏈接和初始化後,它的生命週期就開始了。當 表明類的Class對象不在被引用時,即不可觸及時,Class對象就會結束生命週期,類在方法區內的數據也會被卸載,從而結束類的生命週期。因而可知,一個類什麼時候結束生命週期,取決於表明它的Class對象什麼時候結束生命週期。由Java虛擬機自帶的類加載器所加載的類,在虛擬機的生命週期中,始終不會被卸載。包括根類加載器,擴展類加載器和系統類加載器,Java虛擬機自己會始終引用這些類加載器,而這些類加載器則會始終引用這些類加載器,而這些類加載器則會始終引用它們所加載的類的Class對象,所以這些Class對象始終是可觸及的。
若是程序運行過程當中,將上圖左側三個引用變量都置爲null,此時Sample對象結束生命週期,MyClassLoader對象結束生命週期,表明Sample類的Class對象也結束生命週期,Sample類在方法區內的二進制數據被卸載。
當再次有須要時,會檢查Sample類的Class對象是否存在,若是存在會直接使用,再也不從新加載;若是不存在Sample類會被從新加載,在Java虛擬機的堆區會生成一個新的表明Sample類的Class實例(能夠經過哈希碼查看是不是同一個實例)。
 
 
經過虛擬機參數,能夠查看類的加載與卸載過程
  • -verbose:class 跟蹤類的加載和卸載
  • -XX:+TraceClassLoading 跟蹤類的加載
  • -XX:+TraceClassUnloading 跟蹤類的卸載

 

(1)系統類加載器始終是不會被卸載的,示例以下:
添加虛擬機參數:-verbose:class
 
System.out.println("第一次開始加載Sample類");
Class<?> clazz = ClassLoader.getSystemClassLoader().loadClass(Sample.class.getName());
Object obj = clazz.newInstance();
System.out.println(clazz.hashCode());    // 2018699554
obj = null;
clazz = null;
System.gc();
System.out.println("第二次開始加載Sample類");
clazz = ClassLoader.getSystemClassLoader().loadClass(Sample.class.getName());
System.out.println(clazz.hashCode());    // 2018699554
Thread.sleep(2000);
System.out.println("執行結束....");

控制檯輸出:code

此例也說明,由系統類加載器加載的類不會被卸載,而且只加載一次,Class對象也只有一個對象

 

(2)用戶自定義類加載器能夠卸載,示例以下
添加虛擬機參數:-verbose:class
System.out.println("開始加載Sample類");
MyClassLoader myClassLoader = new MyClassLoader();
Class<?> clazz = myClassLoader.findClass(Sample.class.getName());
Object obj = clazz.newInstance();
// 當表明類的Class對象不在被引用時,Class對象就會結束生命週期,類在方法區內的數據也會被卸載
obj = null;
clazz = null;
myClassLoader = null;
System.gc();
Thread.sleep(2000);
System.out.println("執行結束....");

控制檯輸出:blog

相關文章
相關標籤/搜索