2010-02-26 7 views
38

Мы создаем несколько дочерних загрузчиков классов для загрузки в несколько субприложений в Java-приложение «контейнер», прототипирование горячего развертывания. Когда переменная classpath для определенного загрузчика классов была изменена (т. Е. Баночки были добавлены, удалены, обновлены), старый загрузчик классов отбрасывается (не привязывается) и создается новый загрузчик классов для нового класса маршрутов jars.Когда и как загружается классный загрузчик java для сбора мусора?

После обновления пути к классу, запускающего горячее развертывание, мы взяли кучу кучи. Дамп кучи (с использованием Memory Analyzer) указывает, что старые загрузчики классов не собирались мусором. Некоторые классы в родительском загрузчике классов кэшировали старые загрузчики классов. Следующие вещи были призваны, чтобы очистить эти тайники:

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

Даже после очистки выше кэшей, старые Загрузчики классов еще не мусор. Остальные ссылки на загрузчиком классов были включены следующие:

  • классы, загруженные загрузчиком классов
  • java.lang.Package создали самим загрузчиком классов
  • java.lang.ProtectionDomain создатель самого загрузчиком классов

Все вышеперечисленное относится к циркулярным ссылкам в загрузчике классов, что должно приводить к сбору мусора. Я не уверен, почему это не так. Кто-нибудь знает, почему старые загрузчики классов все еще не собираются мусором, даже с круговыми ссылками?

+0

Какой JVM вы используете (точную версию)? Используете ли вы какие-либо параметры JVM, которые могут повлиять на загрузку классов? Используете ли вы какие-либо вещи из собственных реализаций Sun? Использует ли приложение байт-код? ... Какая среда, которая может повлиять на загрузку классов? – cafebabe

+1

Не связано с вашим главным вопросом, но вы считали что-то вроде OSGi вместо того, чтобы делать свою собственную фреймворк, которая поддерживает горячее развертывание? – SteveD

+0

@bfoo В наших тестах мы используем Java 6. Нет параметров JVM.Мы не используем что-либо в Sun в простейшем случае. Нет манипуляции с байтовым кодом. – onejigtwojig

ответ

15

Я всегда слышал, что выгрузка Classloader была проблематичной. Они составляют theoretically мусор, собранный, когда нет ссылки на экземпляры объекта, и разгрузка классов не требуется, но на практике кажется, что это более проблематично. Тонкие ссылки могут протекать и препятствовать возврату Classloader. На серверах приложений после многочисленных циклов повторного развертывания я иногда получал OutOfMemoryError: PermGen space.

Все, что сказать, что я предполагаю, что существует какая-то неприятная ссылка, которая мешает ей собираться - возможно, анализатор памяти не следил за ссылкой правильно. Похоже, что все это может произойти, как описано в следующих статьях:

Кроме того, я не знаю точно, что вы делаете, но если вы можете ждать JDK 7, вы можете посмотреть на AnonymousClassLoader. Они будут введены для более эффективной поддержки динамического языка, как описано в этой статье:

Я надеюсь, что это поможет.

+0

Одно подзапрос очень прост. Единственной сторонней библиотекой, которую он использует, является log4j. Ничего больше. Остальное - это базовый API JDK. Он также использует класс ResourceBundle, который хранит кеш. После вызова clearCache() эти ссылки исчезли, но он все равно не собирает мусор. Но спасибо за ответ :) – onejigtwojig

+0

ой и кстати, отличные ссылки! – onejigtwojig

+0

Я могу предложить только попробовать простейшее суб-приложение (скажем, с одним классом), а затем добавить все больше и больше классов и зависимостей, чтобы увидеть, в какой момент он останавливает GC загрузчика классов. Но я знаю, что это может быть очень трудоемким. Кстати, Фрэнк Кинет написал также интересные сообщения о транзакциях XA, если вам интересно. – ewernli

Смежные вопросы