2010-02-26 16 views
38

Tworzymy wiele podrzędnych programów ładujących klasy w celu załadowania wielu podrzędnych aplikacji do kontenera aplikacji Java, prototypując szybkie wdrażanie. Kiedy zmieniła się ścieżka klas określonego programu ładującego klasy (tj. Dodano słoiki, usunięto, zaktualizowano), stary program ładujący klasy jest wyrzucany (bez odniesień), a nowy program ładujący klasy jest tworzony dla nowej ścieżki klas słojów.Kiedy i jak jest oznaczany program ładujący klasy java do zbierania śmieci?

Po zaktualizowaniu ścieżki klas, uruchamiając instalację na gorąco, zrobiliśmy zrzut sterty. Zrzut sterty (za pomocą narzędzia Memory Analyzer) wskazuje, że stare programy ładujące klasy nie były gromadzone podczas zbierania śmieci. Niektóre klasy w nadrzędnym programie ładującym klasy buforowały stare programy ładujące klasy. Następujące rzeczy były powoływane w celu usunięcia tych buforów:

java.lang.ResourceBundle.clearCache(classLoader); 
org.apache.commons.logging.LogFactory.release(classLoader); 
java.beans.Introspector.flushCaches(); 

Nawet po usunięciu powyższe bufory, stare classloader wciąż nie są zbierane śmieci. Pozostałe odniesienia do classloader obejmował następujące:

  • klas załadowane przez classloader
  • java.lang.Package stworzonej przez samą classloader
  • java.lang.ProtectionDomain stworzony przez classloader samego

Wszystkie powyższe są odwołaniami cyklicznymi wewnątrz programu ładującego klasy, które powinny wywołać wyrzucanie elementów. Nie jestem pewien, dlaczego tak nie jest. Czy ktokolwiek wie, dlaczego stare programy ładujące klasy nadal nie są zbierane nawet przy odwołaniach cyklicznych?

+0

Którą maszynę JVM używasz (dokładna wersja)? Czy używasz dowolnej opcji maszyny JVM, która może wpływać na ładowanie klas? Czy używasz jakichkolwiek rzeczy z własnych implementacji Sun? Czy aplikacja manipuluje bajtem kodu? ... Jakie środowisko może mieć wpływ na ładowanie klas? – cafebabe

+1

Nie ma związku z głównym pytaniem, ale czy uważasz, że coś w stylu OSGi zamiast tworzyć własne środowisko obsługujące szybkie wdrażanie? – SteveD

+0

@bfoo W naszych testach używamy środowiska Java 6. Brak opcji JVM.W najprostszym przypadku nie korzystamy z impetu firmy Sun. Bez manipulowania bajtowym kodem. – onejigtwojig

Odpowiedz

15

Zawsze słyszałem, że rozładowanie było problematyczne. Są to śmieci zebrane, gdy nie ma odniesienia do instancji obiektu, a rozładunek klas nie jest konieczny, ale w praktyce wydaje się, że jest bardziej problematyczny. Subtelne odniesienia mogą wyciec i zapobiec odzyskaniu Classloader. Na serwerach aplikacji, po wielu cyklach redeploy, czasami otrzymywałem OutOfMemoryError: PermGen space.

Coś, co można powiedzieć, że istnieje gdzieś jakieś paskudne odniesienie, które uniemożliwia ich zbieranie - być może analizator pamięci nie podążył prawidłowo za odnośnikiem. Wydaje się, że to wszystko może się zdarzyć, jak opisano w tych artykułach:

Ponadto, nie wiem dokładnie, co robisz, ale jeśli można poczekać JDK 7, możesz rzucić okiem na AnonymousClassLoader. Zostaną one wprowadzone w celu lepszego wsparcia dynamicznego języka, jak wyjaśniono w tym poście:

Mam nadzieję, że to pomoże.

+0

Jedna podaplikacja jest bardzo prosta. Jedyną biblioteką strony trzeciej, której używa, jest log4j. Nic więcej. Reszta to podstawowe API JDK. Używa również klasy ResourceBundle, która przechowuje pamięć podręczną. Po wywołaniu metody clearCache() referencje zniknęły, ale nadal nie są zbierane śmieci. Ale dzięki za odpowiedź :) – onejigtwojig

+0

oh i przy okazji, świetne linki! – onejigtwojig

+0

Mogę tylko zasugerować, aby spróbować z najprostszą sub-app kiedykolwiek (powiedzmy z jedną klasą), a następnie dodać więcej klas i zależności, aby zobaczyć, w którym momencie zatrzymuje GC klasyloader. Ale wiem, że może to być bardzo czasochłonne. BTW, Frank Kievet napisał także interesujące posty na temat transakcji XA, jeśli jesteś zainteresowany. – ewernli

Powiązane problemy