2013-04-30 14 views
7

moim ostatecznym celem jest możliwość ponownego załadowania klas po ich załadowaniu do maszyny JVM.Rozładowanie programu ładującego klasy

Po przeczytaniu następującej odpowiedzi Unloading classes in java?, próbuję zaimplementować mój własny program ładujący klasy, który sam tworzy inne wystąpienie programu ładującego klasy (tego samego typu) dla każdej ładowanej klasy.

, więc wynikiem jest jedna klasa na jednego Class-Loader.

Celem jest umożliwienie GC klasy, czyli wszystkich jej wystąpień, a następnie zwolnienie jej programu ładującego klasy i umożliwienie ponownego załadowania tej samej klasy z jej bajtów.

Problem polega na tym, - widzę, że moja instancja klasy jest śmieciem zebranym za pomocą metody finalize(), ale nie mogę pobrać programu ładującego klasy ani zebrać śmieci.
Czy istnieje przykład kodu, prosty test, który pokazuje, jak można to zrobić?

dzięki, każda pomoc będzie mile widziane

Edycja:

być jaśniejsze, jestem zainteresowany przykłady kodu gdzie instancji nowych obiektów jest przez "nowego() argumentu , a moduł ładujący klasy nie przeładowuje bezpośrednio klasy w trybie głównym, ale po wywołaniu następnej funkcji "new()".

+0

Po załadowaniu klasy przez niestandardową 'ClassLoader', otrzymasz obiekt' Class'. Niemożliwe jest użycie tego operatora 'nowego'. Użycie 'new' oznacza, że ​​kod został połączony z klasą używaną przez' new', a zatem klasa nie może uzyskać śmieci zebranych, gdy twój kod zawierający wyrażenie 'new' jest nadal aktywny. W tym miejscu musisz użyć Reflection, np. wywołaj 'newInstance()' na 'Class'. Oczywiście dynamicznie ładowany kod może sam używać 'new' do tworzenia instancji klas w swoim własnym zakresie. – Holger

Odpowiedz

9

Ładowanie klas ładujących powinno być zbędne, jeśli nie ma już do nich odnośników. Wziąłem this code z @PeterLawrey (dzięki) (to nie to samo jak ty), umieścić dziennik w niestandardowej klasy ładowarka finalize() metody i voila, że ​​ładowarki klasy śmieci są zbierane po ich załadowanej klasy jest 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

Dzięki, byłem bardziej zainteresowany przykładami kodu, które pokazują instantioan klas za pomocą operandu new(), przepraszam, że nie jest jasne w moim pytaniu, będę je edytować. –

1

W przypadku innych rzeczy różne są rozładowania programu ładującego klasy tylko podczas globalnego gc. Może to prowadzić do długich czasów pauzy w globalnym gc i do braku pamięci, gdy tworzonych jest wiele programów ładujących klasy w postaci . Napotkano ten problem z JMXMP, w którym tworzone jest jedno wystąpienie programu ładującego klasy com.sun.jmx.remote.opt.util.OrderClassLoaders dla każdej wiadomości zdalnej typu MBeanServerRequestMessage.CREATE_MBEAN_LOADER_PARAMS.

Powiązane problemy