Разгрузка классов в Java?

У меня есть пользовательский загрузчик классов, чтобы приложение для настольных компьютеров могло динамически начинать загрузку классов с сервера приложений, с которым мне нужно поговорить. Мы сделали это, так как количество банок, необходимых для этого, просто смешно (если мы хотим отправить их). У нас также возникают проблемы с версиями, если мы не загружаем классы динамически во время выполнения из библиотеки AppServer.

Теперь я столкнулся с проблемой, когда мне нужно поговорить с двумя разными AppServer и обнаружил, что в зависимости от того, чьи классы я загружаю в первую очередь, я могу плохо сломаться... Есть ли способ принудительной выгрузки класса без фактического уничтожения JVM?

Надеюсь, это имеет смысл

7 ответов

Решение

Единственный способ, которым Класс может быть выгружен, это если используемый Classloader является сборщиком мусора. Это означает, что ссылки на каждый отдельный класс и на самого загрузчика классов должны идти по пути додо.

Одним из возможных решений вашей проблемы является наличие Classloader для каждого файла JAR и Classloader для каждого из AppServers, который делегирует фактическую загрузку классов конкретным загрузчикам классов Jar. Таким образом, вы можете указать разные версии файла JAR для каждого сервера приложений.

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

Если вы не хотите использовать OSGI, одной из возможных реализаций может быть использование одного экземпляра класса JarClassloader для каждого файла JAR.

И создайте новый класс MultiClassloader, который расширяет Classloader. Этот класс внутренне будет иметь массив (или List) JarClassloaders, а в методе defineClass() будет перебирать все внутренние загрузчики классов до тех пор, пока не будет найдено определение или не будет сгенерировано исключение NoClassDefFoundException. Для добавления новых классов JarClassloaders в класс может быть предоставлена ​​пара методов доступа. Существует несколько возможных реализаций в сети для MultiClassLoader, так что вам может даже не потребоваться написать свою собственную.

Если вы создаете экземпляр MultiClassloader для каждого соединения с сервером, в принципе возможно, что каждый сервер использует разные версии одного и того же класса.

Я использовал идею MultiClassloader в проекте, где классы, которые содержали пользовательские сценарии, должны были загружаться и выгружаться из памяти, и это работало довольно хорошо.

Да, есть способы загрузить классы и "выгружать" их позже. Хитрость заключается в том, чтобы реализовать свой собственный загрузчик классов, который находится между загрузчиком классов высокого уровня (загрузчиком классов System) и загрузчиками классов серверов приложений, и надеяться, что загрузчики классов сервера приложений делегируют загрузку классов верхним загрузчикам.,

Класс определяется его пакетом, его именем и загрузчиком классов, который он первоначально загрузил. Запрограммируйте загрузчик классов "прокси", который загружается первым при запуске JVM. Процедура:

  • Программа запускается и настоящий "основной" класс загружается этим прокси-загрузчиком классов.
  • Каждый класс, который затем обычно загружается (т.е. не через другую реализацию загрузчика классов, которая может нарушить иерархию), будет делегирован этому загрузчику классов.
  • Прокси-класс загрузчика делегатов java.x а также sun.x в системный загрузчик классов (они не должны загружаться через какой-либо другой загрузчик классов, кроме системного загрузчика классов).
  • Для каждого заменяемого класса создайте экземпляр загрузчика классов (который действительно загружает класс и не делегирует его родительскому загрузчику классов) и загрузите его через него.
  • Сохраните пакет / имя классов как ключи и загрузчик классов как значения в структуре данных (т.е. Hashmap).
  • Каждый раз, когда прокси-загрузчик классов получает запрос на класс, который был загружен ранее, он возвращает класс из загрузчика классов, сохраненного ранее.
  • Этого должно быть достаточно, чтобы найти байтовый массив класса вашим загрузчиком классов (или "удалить" пару ключ / значение из вашей структуры данных) и перезагрузить класс на случай, если вы захотите его изменить.

Сделано прямо там, не должно прийти ClassCastException или LinkageError и т. Д.

Для получения дополнительной информации об иерархиях загрузчиков классов (да, это именно то, что вы реализуете здесь;-) посмотрите на "Серверное программирование на Java" Теда Ньюарда - эта книга помогла мне реализовать нечто очень похожее на то, что вы хотите.

Я написал собственный загрузчик классов, из которого можно выгружать отдельные классы без GCing загрузчика классов. Jar Class Loader

Загрузчики классов могут быть сложной проблемой. В частности, вы можете столкнуться с проблемами, если вы используете несколько загрузчиков классов, и их взаимодействие четко и строго не определено. Я думаю, что для того, чтобы действительно иметь возможность выгрузить класс, который вы собираетесь использовать, необходимо удалить все ссылки на любые классы (и их экземпляры), которые вы пытаетесь выгрузить.

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

Вы можете выгрузить ClassLoader, но вы не можете выгрузить определенные классы. Более конкретно, вы не можете выгружать классы, созданные в ClassLoader, который не находится под вашим контролем.

Если возможно, я предлагаю использовать свой собственный ClassLoader, чтобы вы могли выгрузить.

Классы имеют неявную строгую ссылку на свой экземпляр ClassLoader, и наоборот. Они мусор, как с объектами Java. Без использования интерфейса инструментов или подобного вы не сможете удалить отдельные классы.

Как всегда, вы можете получить утечки памяти. Любая сильная ссылка на один из ваших классов или загрузчик классов утечет все это. Это происходит, например, с реализациями Sun ThreadLocal, java.sql.DriverManager и java.beans.

Если вы в прямом эфире смотрите, работает ли класс выгрузки в JConsole или что-то еще, попробуйте также добавить java.lang.System.gc() в конце вашего класса логика выгрузки. Он явно запускает сборщик мусора.

Другие вопросы по тегам