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

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

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

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

Ответ 1

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

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

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

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

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

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

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

Ответ 2

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

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

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

Сделано прямо там не должно быть ClassCastException или LinkageError и т.д.

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

Ответ 3

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

Ответ 4

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

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

Ответ 5

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

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

Ответ 6

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

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

Ответ 7

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