Загрузка классов Java работает очень медленно? - PullRequest
7 голосов
/ 22 мая 2009

Я пытаюсь динамически загрузить файл Java .class и вызвать его по отражению.

У меня есть класс под названием Foo; он имеет пустой конструктор и имеет один метод с именем doit (), который принимает аргумент String и возвращает String. Также он переворачивает строку.

Вот мой код:

    URL url = new URL("file://C:/jtest/");
    URLClassLoader loader = new URLClassLoader(new URL[]{url});
    Class<?> cl = loader.loadClass("Foo");
    Constructor<?> cons = cl.getConstructor((Class[])null);
    Object ins = cons.newInstance(new Object[]{});
    Method meth = cl.getDeclaredMethod("doit", String.class);
    Object ret = meth.invoke(ins, new Object[]{"!dlroW olleH"});
    System.out.println((String)ret);

Как и следовало ожидать, это печатает «Hello World!». Тем не менее, это займет около 30 секунд для завершения. Я знаю, что отражение медленное, но я ожидаю, что оно будет 10 мс или около того.

Я использую Eclipse с JRE 1.6.0_13 и использую Windows Vista.

Что я здесь не так делаю?

Спасибо.

Редактировать: Я профилировал код, и все его время используется в третьей строке (loadClass ()). Все остальное происходит мгновенно.

Редактировать: Я поместил код в цикл; Функция замедления каким-то образом оптимизируется и занимает только 30 секунд в первом цикле.

Редактировать: Я нашел решение.

Вместо:

URL url = new URL("file://C:/jtest/");

Я изменил его на:

URL url = new URL("file:/C:/jtest/");

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

Ответы [ 6 ]

6 голосов
/ 30 сентября 2009

Для вашей информации: Может быть, немного поздно для вас, но я наткнулся на ту же проблему и нашел этот пост.

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

Я попробовал следующее:

URL url = новый URL ("file: // localhost / C: / jtest /");

и это работает (почти) так же быстро, как ваше решение с одним слешем.

5 голосов
/ 22 мая 2009

Через 30 секунд вы сможете «профилировать» свой код и точно определить, в чем заключается проблема (в загрузке класса, создании экземпляра, поиске метода и т. Д.).

Поскольку это занимает 30 секунд (и не намного меньше, порядка 10 мс или около того), вы можете просто использовать System.out.println(new Date()); между каждой строкой кода.

Я подозреваю, что вы обнаружите, что loader.loadClass (String) занимает так много времени - и я подозреваю, что вы обнаружите, что у вас либо очень длинный путь к классу, либо путь к классу, который включает сетевой ресурс какого-то рода. 1006 *

5 голосов
/ 22 мая 2009

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

3 голосов
/ 22 мая 2009

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

Редактировать : Круто, исходя из вашего профилирования, звучит так, будто вы приближаетесь к основной причине. Еще одна вещь, которую следует учитывать, если вы используете библиотеки, которые имеют большие затраты на запуск. Я использую iBatis для управления нашими взаимодействиями с Oracle, и при первом запуске он считывает несколько файлов XML и обрабатывает в них шаблоны запросов. Есть заметное отставание. Было бы интересно услышать, что вы узнали, но вы можете решить, что стоимость единовременного переноса приемлема.

2 голосов
/ 22 мая 2009

Можно ли поместить Foo в CLASSPATH по умолчанию, чтобы вы могли просто использовать что-то вроде:

ClassLoaderTest.class.getClassLoader()

, где ClassLoaderTest - это класс, в котором вы работаете. Или, если вы не работаете в статическом контексте, тогда:

this.getClass().getClassLoader()`  

Любой из них спасет вас от создания нового загрузчика классов.

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

РЕДАКТИРОВАТЬ: Поскольку loadClass занимает большую часть времени, может быть, C: \ jtest загроможден. Вы можете попробовать поместить Foo.class в каталог и использовать его в качестве URL. Конечно, причина, по которой он работает быстрее во второй раз, заключается в том, что Foo уже загружен.

2 голосов
/ 22 мая 2009

В вашем коде нет ничего плохого ... Я смог скомпилировать вашу программу менее чем за секунду. Я использую Java 1.6.11 в Vista Business.

Возможно, ваш public string doit(string arg) метод - это то, что занимает так много времени. Можете ли вы попробовать вызвать его, не используя рефлексию, чтобы увидеть, занимает ли это много времени? Попробуйте doit() просто вернуть параметр, который вы передаете (а не инвертировать символы), чтобы увидеть, замедляет ли ваш алгоритм реверсирования.

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