Mam niestandardowy moduł ładujący klasy, dzięki czemu aplikacja komputerowa może dynamicznie rozpoczynać ładowanie klas z serwera aplikacji, z którym muszę porozmawiać. Zrobiliśmy to, ponieważ ilość słoików, które są do tego potrzebne, jest absurdalna (gdybyśmy chcieli je wysłać). Mamy również problemy z wersją, jeśli nie ładujemy klas dynamicznie w czasie wykonywania z biblioteki AppServer.
Teraz po prostu napotkałem problem, w którym muszę porozmawiać z dwoma różnymi serwerami aplikacji i stwierdziłem, że w zależności od tego, czyje klasy załaduję najpierw, mogę źle się zepsuć ... Czy istnieje sposób, aby wymusić wyładowanie klasy bez faktycznego zabijania JVM?
Mam nadzieję, że to ma sens
java
classloader
el_eduardo
źródło
źródło
Odpowiedzi:
Jedynym sposobem, w jaki można zwolnić Class, jest to, że używany Classloader jest usuwany z pamięci. Oznacza to, że odniesienia do każdej klasy i samego modułu ładującego klasy muszą iść drogą dodo.
Jednym z możliwych rozwiązań problemu jest posiadanie modułu ładującego klasy dla każdego pliku jar i modułu ładującego klasy dla każdego serwera AppServers, który deleguje rzeczywiste ładowanie klas do określonych programów ładujących klasy Jar. W ten sposób możesz wskazać różne wersje pliku jar dla każdego serwera aplikacji.
Nie jest to jednak trywialne. Platforma OSGi stara się właśnie to zrobić, ponieważ każdy pakiet ma inny program ładujący klasy, a zależności są rozwiązywane przez platformę. Może dobrym rozwiązaniem byłoby przyjrzenie się temu.
Jeśli nie chcesz używać OSGI, jedną z możliwych implementacji może być użycie jednej instancji klasy JarClassloader dla każdego pliku JAR.
I utwórz nową klasę MultiClassloader, która rozszerza Classloader. Ta klasa wewnętrznie miałaby tablicę (lub Listę) JarClassloaders, aw metodzie defineClass () iterowałaby przez wszystkie wewnętrzne programy ładujące do momentu znalezienia definicji lub wyrzucenia wyjątku NoClassDefFoundException. Można udostępnić kilka metod akcesorów, aby dodać nowe elementy JarClassloaders do klasy. Istnieje kilka możliwych implementacji MultiClassLoadera w sieci, więc możesz nawet nie potrzebować pisać własnej.
Jeśli instalujesz MultiClassloader dla każdego połączenia z serwerem, w zasadzie możliwe jest, że każdy serwer używa innej wersji tej samej klasy.
Wykorzystałem pomysł MultiClassloader w projekcie, w którym klasy zawierające skrypty zdefiniowane przez użytkownika musiały być ładowane i wyładowywane z pamięci i działało całkiem dobrze.
źródło
Tak, istnieją sposoby na załadowanie klas i późniejsze ich „wyładowanie”. Sztuczka polega na zaimplementowaniu własnego modułu ładującego klasy, który znajduje się między programem ładującym klasy wysokiego poziomu (moduł ładujący klasy System) a programami ładującymi klasy serwera (serwerów) aplikacji i mieć nadzieję, że programy ładujące klasy serwera aplikacji delegują ładowanie klas do modułów ładujących wyższych .
Klasa jest definiowana przez jej pakiet, jej nazwę i program ładujący klasę, który został pierwotnie załadowany. Zaprogramuj program ładujący klasy „proxy”, który jest pierwszym ładowanym podczas uruchamiania maszyny JVM. Przepływ pracy:
java.x
isun.x
moduł ładujący klasy systemu ( nie mogą być ładowani przez żaden inny program ładujący klasy niż systemowy moduł ładujący).Sporządzono w tym miejscu, nie powinien pojawić się wyjątek ClassCastException lub LinkageError itp.
Aby uzyskać więcej informacji na temat hierarchii ładujących klas (tak, właśnie to tutaj implementujesz; -) spójrz na „Server-Based Java Programming” Teda Newarda - ta książka pomogła mi zaimplementować coś bardzo podobnego do tego, czego chcesz.
źródło
ClassLoader
na klasę to trochę za dużo, jedenClassLoader
na JAR ma sens. Czy może być bardziej szczegółowe informacje o tym, jak wymusić przesyłanie zajęć w proponowanym schemacie? Np. Jak mogę zagwarantować, że instancje klas ładowane przez ClassLoaderA nie są odwoływane przez instancje ładowane przez ClassLoaderB?Napisałem własny classloader, z którego można wyładować poszczególne klasy bez GCing the classloader. Jar Class Loader
źródło
JarClassLoader
dla każdego załadowanego pliku jar, możesz go wywołaćgetLoadedClasses()
, a następnie iterować po każdym i wyładować.Classloadery mogą być trudnym problemem. Możesz napotkać problemy szczególnie, jeśli używasz wielu programów ładujących klasy i nie masz jasno i rygorystycznie zdefiniowanych ich interakcji. Myślę, że aby rzeczywiście móc wyładować klasę, którą zamierzasz, musisz usunąć wszystkie odwołania do klas (i ich instancji), które próbujesz usunąć.
Większość ludzi, którzy muszą robić tego typu rzeczy, korzysta z OSGi . OSGi jest naprawdę potężny i zaskakująco lekki i łatwy w użyciu,
źródło
Możesz zwolnić ClassLoader, ale nie możesz zwolnić określonych klas. Mówiąc dokładniej, nie można zwolnić klas utworzonych w ClassLoader, nad którymi nie masz kontroli.
Jeśli to możliwe, sugeruję użycie własnego ClassLoadera, abyś mógł rozładować.
źródło
Klasy mają niejawne silne odwołanie do ich wystąpienia ClassLoader i na odwrót. Są zbierane jako śmieci, tak jak w przypadku obiektów Java. Bez wciskania interfejsu narzędzi lub podobnego, nie możesz usunąć poszczególnych klas.
Jak zawsze możesz mieć wycieki pamięci. Każde silne odniesienie do jednej z twoich klas lub programu ładującego klasy spowoduje wyciek całej sprawy. Dzieje się tak na przykład w przypadku implementacji ThreadLocal, java.sql.DriverManager i java.beans firmy Sun.
źródło
Jeśli oglądasz na żywo, czy wyładowywanie zajęć działało w JConsole, czy coś w tym stylu, spróbuj również dodać
java.lang.System.gc()
na końcu logiki wyładowywania klasy. To jawnie uruchamia Garbage Collector.źródło