2013-04-30 141 views
7

我的最終目標是能夠在它們已經加載到JVM之後重新加載類。卸載類加載器

閱讀以下答案Unloading classes in java?後,我一直在嘗試實現我自己的類加載器,它自己爲它加載的每個類創建不同的類加載器實例(它自己的類型相同)。

所以,每個Class-Loader的結果是一個類。

其目的是爲了能夠GC類,即它的所有實例,然後卸載它的類加載器,並能夠從它的字節重新加載相同的類。

問題是 - 我可以看到我的類實例被垃圾收集使用finalize()方法,但我不能讓我的類加載器卸載,或垃圾收集。
是否有任何代碼示例,一個簡單的測試,顯示它可以如何完成?

感謝,任何幫助,將不勝感激

編輯

更清晰,我感興趣的代碼示例,其中新對象的實例化是通過「新的()」操作數,並且類加載器沒有顯式地重載主類中的類,但是在下一個'new()'被調用之後。

+0

當你通過自定義的'ClassLoader'加載一個類時,你會得到一個'Class'對象。用這個'new'運算符是不可能的。使用'new'意味着你的代碼已經與'new'使用的類相關聯,因此,當你的包含'new'表達式的代碼仍然處於活動狀態時,該類不會被垃圾收集。此時你必須使用反射,例如在'Class'上調用'newInstance()'。當然,動態加載的代碼本身可以使用'new'來在它自己的範圍內實例化類。 – Holger 2018-01-25 09:33:39

回答

9

如果沒有更多的引用,那麼類加載器應該被垃圾回收。我把this code從@PeterLawrey(感謝)(它同樣的事情你),把日誌中的自定義類加載器finalize()方法,瞧,類加載器的垃圾自己加載類後收集到的GC:

/* Copyright (c) 2011. Peter Lawrey 
* 
* "THE BEER-WARE LICENSE" (Revision 128) 
* As long as you retain this notice you can do whatever you want with this stuff. 
* If we meet some day, and you think this stuff is worth it, you can buy me a beer in return 
* There is no warranty. 
*/ 


import java.lang.reflect.Field; 
import java.net.URL; 
import java.net.URLClassLoader; 

public class LoadAndUnloadMain { 
    public static void main(String... args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InterruptedException { 
     URL url = LoadAndUnloadMain.class.getProtectionDomain().getCodeSource().getLocation(); 
     final String className = LoadAndUnloadMain.class.getPackage().getName() + ".UtilityClass"; 
     { 
      ClassLoader cl; 
      Class clazz; 

      for (int i = 0; i < 2; i++) { 
       cl = new CustomClassLoader(url); 
       clazz = cl.loadClass(className); 
       loadClass(clazz); 

       cl = new CustomClassLoader(url); 
       clazz = cl.loadClass(className); 
       loadClass(clazz); 
       triggerGC(); 
      } 
     } 
     triggerGC(); 
    } 

    private static void triggerGC() throws InterruptedException { 
     System.out.println("\n-- Starting GC"); 
     System.gc(); 
     Thread.sleep(100); 
     System.out.println("-- End of GC\n"); 
    } 

    private static void loadClass(Class clazz) throws NoSuchFieldException, IllegalAccessException { 
     final Field id = clazz.getDeclaredField("ID"); 
     id.setAccessible(true); 
     id.get(null); 
    } 

    private static class CustomClassLoader extends URLClassLoader { 
     public CustomClassLoader(URL url) { 
      super(new URL[]{url}, null); 
     } 

     @Override 
     protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { 
      try { 
       return super.loadClass(name, resolve); 
      } catch (ClassNotFoundException e) { 
       return Class.forName(name, resolve, LoadAndUnloadMain.class.getClassLoader()); 
      } 
     } 

     @Override 
     protected void finalize() throws Throwable { 
      super.finalize(); 
      System.out.println(this.toString() + " - CL Finalized."); 
     } 
    } 
} 

class UtilityClass { 
    static final String ID = Integer.toHexString(System.identityHashCode(UtilityClass.class)); 
    private static final Object FINAL = new Object() { 
     @Override 
     protected void finalize() throws Throwable { 
      super.finalize(); 
      System.out.println(ID + " Finalized."); 
     } 
    }; 

    static { 
     System.out.println(ID + " Initialising"); 
    } 
} 
+0

謝謝,我更感興趣的代碼示例,通過'new()'操作數顯示類的instantioan,抱歉不清楚我的問題,我會編輯它。 – 2013-04-30 20:18:39

1

IBM J9 VM事情是不同的,因爲類加載器卸載只發生在全局gc期間。這可能會導致全局gc中的大量暫停時間,以及正在創建的大量類裝入器時,會導致內存不足。我遇到了JMXMP的這種問題,其中爲類型爲MBeanServerRequestMessage.CREATE_MBEAN_LOADER_PARAMS的每個遠程消息創建了一個com.sun.jmx.remote.opt.util.OrderClassLoaders類加載器實例。