2009-05-22 3 views
7

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

У меня есть класс под названием Foo; он имеет пустой конструктор и имеет один метод, называемый doit(), который принимает аргумент 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 человек) мог пропустить это. Теперь я чувствую себя немым.

+1

loadClass сначала проверяет кеш, чтобы узнать, загружен ли класс, если я правильно помню. Это объясняет, почему это не займет много времени на второй итерации. –

+0

Является ли настоящий «Foo» в пакете? Загрузка из пакета по умолчанию (без пакета) может иметь странные эффекты. Попробуйте перейти к foo.Foo. – flicken

+0

Это интересный ... новый URL («файл:/C:/jtest /»). GetPath() is/C:/jtest /. Интересно, как это интерпретирует URLClassLoader. –

ответ

5

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

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

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

+2

@unknown: в этом случае (и если вы решили проблему), вы должны опубликовать ответ, который, как вы знаете, правильный, и принять его. –

5

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

+0

Как мне это сделать? – Lucky

+0

echo% CLASSPATH% в командной строке –

+0

или проверить настройки в Eclipse –

2

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

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

+0

Он сказал, что потребовалось 30 секунд. Я предполагаю, что это означает завершить выполнение, а не компилировать. –

+0

Скомпилирован и работает менее чем за секунду. Вот почему я сказал ему попробовать выполнить его с другой реализацией его метода doit(). – Cuga

+0

doit() возвращается сразу при использовании неотражающий код. – Lucky

3

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

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

2

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

ClassLoaderTest.class.getClassLoader() 

, где ClassLoaderTest класса вы работаете в Or, при условии, если вы. не работает в статическом контексте, то:

this.getClass().getClassLoader()` 

Любой из них сохранит вас инстанцировании новый загрузчик класса.

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

EDIT: Поскольку loadClass занимает большую часть времени, может случиться, что C: \ jtest загроможден. Вы можете попробовать помещать Foo.class в директорию и использовать это как URL-адрес. Конечно, причина, по которой во второй раз быстрее, заключается в том, что Foo уже загружен.

6

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

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

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

URL URL = новый URL ("файл: // локальный/C:/Jtest /");

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

+0

Сохранено мне 4 минуты работы и часы вытягивания волос – MonoThreaded

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