Как мне «закрыть» ClassLoader? - PullRequest
9 голосов
/ 20 сентября 2011

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

Когда скрипт завершается, я хочу «выгрузить» или «закрыть» загрузчик классов, чтобы освободить ресурсы.

Достаточно ли установить ссылку на загрузчик классов на null? Мне особенно интересно, не закончатся ли в конечном итоге файловые дескрипторы, потому что дополнительные классы находятся в файлах JAR.

PS: должен работать с Java 5 и выше. Да, я знаю ...

Ответы [ 6 ]

7 голосов
/ 28 июня 2014

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

В Java 7 был использован метод close () добавлен в URLClassLoader, это именно то, что запрашивал OP.

EDIT (благодаря @Hot Licks) : ОК, так что это не именно то, о чем просил ОП.Это не освобождает все ресурсы, или делает ресурсы и загрузчик коллекционируемыми.Это просто предотвращает загрузку большего количества ресурсов с помощью загрузчика классов.Он делает , однако закрывает файл JAR, который был загружен с URLClassLoader.

4 голосов
/ 20 сентября 2011

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

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

[Обратите внимание, что удаление ссылок на класс нетривиально.Любой другой класс, который ссылается на него по имени, конечно, предотвратит удаление.Поэтому класс должен быть загружен с использованием ClassLoader.findClass или чего-то подобного.]

3 голосов
/ 29 июня 2015

Если вы не можете использовать Java7 и его метод close (), используйте отражение, чтобы закрыть все открытые архивы JAR загрузчика классов, например:

public void close() {
try {
   Class clazz = java.net.URLClassLoader.class;
   java.lang.reflect.Field ucp = clazz.getDeclaredField("ucp");
   ucp.setAccessible(true);
   Object sun_misc_URLClassPath = ucp.get(this);
   java.lang.reflect.Field loaders = 
      sun_misc_URLClassPath.getClass().getDeclaredField("loaders");
   loaders.setAccessible(true);
   Object java_util_Collection = loaders.get(sun_misc_URLClassPath);
   for (Object sun_misc_URLClassPath_JarLoader :
        ((java.util.Collection) java_util_Collection).toArray()) {
      try {
         java.lang.reflect.Field loader = 
            sun_misc_URLClassPath_JarLoader.getClass().getDeclaredField("jar");
         loader.setAccessible(true);
         Object java_util_jar_JarFile = 
            loader.get(sun_misc_URLClassPath_JarLoader);
         ((java.util.jar.JarFile) java_util_jar_JarFile).close();
      } catch (Throwable t) {
         // if we got this far, this is probably not a JAR loader so skip it
      }
   }
} catch (Throwable t) {
   // probably not a SUN VM
}
return;
}
3 голосов
/ 20 сентября 2011

Если у вас больше нет классов (и объектов), загруженных из этого загрузчика классов, и если вы не сохраняете никаких ссылок на этот загрузчик классов, он будет автоматически обрабатываться сборщиком мусора.

1 голос
/ 20 сентября 2011

Нет методов close () в загрузчике классов URL или любых его родительских классах, так что вам не повезло.

Разве GC не должен это обрабатывать?

0 голосов
/ 05 июля 2012

Я расширил URLClassLoader и создал метод close, основанный на Java 7s. Я хотел разработать своего IRC бота на своем iPad 2, поэтому я сделал то, что было нужно. Теперь моя система плагинов стабильна на Java 6 и 7, ура.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...