2013-04-30 7 views
7

Mein Endziel ist es, Klassen neu laden zu können, nachdem sie bereits in die JVM geladen wurden.Entladen eines Klassenladers

Nachdem ich die folgende Antwort Unloading classes in java? gelesen habe, habe ich versucht, meinen eigenen Class-Loader zu implementieren, der für jede geladene Klasse selbst eine andere Instanz von Class-Loader (derselben Art von eigenen) erstellt.

Also, das Ergebnis ist eine Klasse pro Klasse-Loader.

Der Zweck ist in der Lage zu GC die Klasse, dh alle seine Instanzen, dann zu entladen seinen Klassenlader, und in der Lage, die gleiche Klasse aus seinen Bytes neu zu laden.

Das Problem ist - Ich kann sehen, meine Klasse Instanz wird Garbage Collected mit Finalize() -Methode, aber ich kann nicht meine Class-Loader entladen oder Müll gesammelt werden.
Gibt es ein Codebeispiel, einen einfachen Test, der zeigt, wie es gemacht werden kann?

sein klarer, ich bin an Code-Beispiele, wo die Instanziierung der neuen Objekte über die ‚neue()‘ ist Operand:

Dank, würde jede mögliche Hilfe

bearbeiten geschätzt werden , und der Class-Loader lädt die Klasse nicht explizit im main, sondern nach dem nächsten 'new()'.

+0

Wenn Sie eine Klasse über einen benutzerdefinierten 'ClassLoader' laden, erhalten Sie ein' Class'-Objekt. Es ist unmöglich, den "neuen" Operator damit zu verwenden. Die Verwendung von 'new' bedeutet, dass der Code mit der von' new' verwendeten Klasse verknüpft wurde. Daher kann die Klasse keine Garbage Collection erhalten, wenn der Code mit dem Ausdruck 'new' noch aktiv ist. Sie müssen Reflection an diesem Punkt verwenden, z. Rufen Sie 'newInstance()' in der 'Class' auf. Natürlich kann der dynamisch geladene Code selbst "neu" verwenden, um Klassen in seinem eigenen Umfang zu instanziieren. – Holger

Antwort

9

Die Klasse Loader sollte Müll gesammelt werden, wenn es keine Verweise mehr gibt. Ich nahm this code von @PeterLawrey (danke) (es tut dasselbe wie bei Ihnen), ein Protokoll im Loader finalize() Methode benutzerdefinierte Klasse setzen und voila, wird die Klassenlader Müll nach der geladenen Klasse gesammelt ist 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

Danke, ich war mehr an Codebeispielen interessiert, die Instantioan von Klassen über den 'new()' Operanden zeigen, tut mir leid, dass ich in meiner Frage nicht klar bin, ich werde es bearbeiten. –

1

In IBM J9 VM Dinge sind anders als Klassenlader entladen nur während einer globalen GC auftritt. Dies kann zu großen Pausenzeiten in einem globalen GC und zu wenig Speicher führen, wenn eine große Anzahl von Klassenladeprogrammen erstellt wird. Ich habe diese Probleme mit JMXMP, wo eine Instanz com.sun.jmx.remote.opt.util.OrderClassLoaders Classloader für jede remote-Nachricht des Typs MBeanServerRequestMessage.CREATE_MBEAN_LOADER_PARAMS erstellt wird aufgetreten.