2013-04-30 6 views
7

il mio obiettivo finale è poter ricaricare le classi dopo che sono state già caricate sulla JVM.Scaricare un classloader

Dopo aver letto la seguente risposta Unloading classes in java?, ho cercato di implementare il proprio Class-Loader, che a sua volta crea una diversa istanza di Class-Loader (stesso tipo di proprio) per ogni classe che carica.

quindi, il risultato è una classe per un caricatore di classi.

Lo scopo è essere in grado di eseguire il comando GC della classe, ovvero tutte le sue istanze, quindi di scaricare il suo programma di caricamento classi e di poter ricaricare la stessa classe dai suoi byte.

il problema è - posso vedere la mia istanza di classe di essere garbage collection utilizzando finalizzare il metodo(), ma non posso ottenere la mia classe-Loader per scaricare, o per essere garbage collection.
c'è qualche esempio di codice, un semplice test, che mostra come può essere fatto?

grazie, tutto l'aiuto sarebbe apprezzato

Edit:

essere più chiari, sono interessato esempi di codice in cui l'istanziazione dei nuovi oggetti avviene tramite il 'nuovo) (' operando e Class-loader non sta caricando esplicitamente la classe nel main, ma dopo il successivo 'new()' viene chiamato.

+0

Quando si carica una classe tramite un 'ClassLoader' personalizzato, si otterrà un oggetto' Class'. È impossibile usare l'operatore 'new' con quello. L'uso di 'new' implica che il codice è stato collegato alla classe usata da' new' e quindi, la classe non può ottenere la garbage collection quando il codice che contiene l'espressione 'new' è ancora attivo. Devi usare Reflection a questo punto, ad es. invoca 'newInstance()' su 'Class'. Ovviamente, il codice caricato dinamicamente può usare 'new' per istanziare classi all'interno del proprio ambito. – Holger

risposta

9

I programmi di caricamento classe devono essere raccolti automaticamente se non vi sono più riferimenti a essi. Ho preso this code da @PeterLawrey (grazie) (si fa la stessa cosa come la vostra), mettere un registro nel metodo classe personalizzata loader finalize() e voilà, i caricatori di classe sono rifiuti raccolti dopo la loro classe caricata è 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

Grazie, ero più interessato agli esempi di codice che mostravano instantioan delle classi tramite l'operando 'new()', scusa per non essere chiaro nella mia domanda, lo modificherò. –

1

In IBM J9 VM le cose sono diverse poiché lo scaricamento del classloader si verifica solo durante un gc globale. Questo può portare a tempi di pausa enormi in un gc globale e alla memoria insufficiente quando c'è un gran numero di programmi di caricamento classe che si stanno creando. Ho riscontrato questo problema con JMXMP dove viene creata un'istanza del classloader com.sun.jmx.remote.opt.util.OrderClassLoaders per ciascun messaggio remoto di tipo MBeanServerRequestMessage.CREATE_MBEAN_LOADER_PARAMS.