Проблемы с производительностью при вызове java.beans.Introspector.getBeanInfo после неактивности

Я использую стороннюю библиотеку, которая динамически создает экземпляры классов Java и заполняет эти экземпляры с помощью Introspector.getBeanInfo . Некоторые запросы могут привести к 5 или 6 последовательным вызовам Introspector.getBeanInfo . Я обнаружил, что, когда приложение простаивает около часа или около того, первый вызов Introspector.getBeanInfo требует значительно большего времени для выполнения (20-60 секунд) по сравнению с последующими вызовами (<100 миллисекунд). ). Звонки, сделанные в течение следующих нескольких минут, по-прежнему занимают <100 миллисекунд, но когда я жду еще час, первый звонок снова занимает 20-60 секунд.

Пытаясь воссоздать поведение с помощью простого тестового приложения, я обнаружил аналогичное поведение, когда само приложение Java не запускалось в течение часа. Например, если я запустил следующее консольное приложение, это может занять 15 миллисекунд. Если я затем подожду час и снова запущу приложение, это займет 20 секунд.

long start = System.currentTimeMillis();
System.out.println("Start");
Introspector.getBeanInfo(MyClass.class, Object.class);
long end = System.currentTimeMillis();
System.out.println("End: " + (end-start));

Первоначально я думал, что проблема может быть связана с тем фактом, что класс Introspector пытается создать экземпляры классов на основе стандартных соглашений об именах, которые не существуют в моем приложении (например, MyClassBeanInfo ), и сканирование файлов jar в попытке найти эти классы занимало много времени (в моем приложении java чуть более 100 файлов jar, на которые есть ссылки) , но я вызвал Introspector.getBeanInfo (MyClass.class, Object.class, Introspector. IGNORE_ALL_BEANINFO) с использованием отражения (это частный метод в Sun JRE, который, глядя на код, кажется, пропускает поиск классов BeanInfo), и я все еще мог воспроизвести задержку.

Я также искал для получения информации о любом типе кеша JRE / JVM jar, но еще не нашли ничего, что могло бы объяснить такое поведение. Кто-нибудь знает, почему это ведет себя именно так, и могу ли я что-нибудь сделать, чтобы это исправить?

В качестве примечания я использую JDK 1.6.0_21 в Windows XP. Я использую стороннюю библиотеку BlazeDS. Мое приложение размещено в Tomcat с использованием интеграции Spring / BlazeDS. Я перезаписал несколько классов BlazeDS, чтобы точно определить, где была задержка (это вызов Introspector. getBeanInfo в методе getPropertyDescriptorCacheEntry из flex.messaging.io.BeanProxy ). Кроме того, BlazeDS кэширует BeanInfo, поэтому вызовы Introspector.getBeanInfo выполняются только тогда, когда Blaze десериализует объект, сопоставленный с классом Java, который еще не обработан. Итак, у меня есть другие способы обойти эту проблему, но я действительно хотел бы знать, есть ли допустимое объяснение такого поведения.

РЕДАКТИРОВАТЬ: Я запускал jstack для процесса несколько раз, воспроизводя проблему (спасибо @Tom), и подтвердил, что это связано с загрузкой файлов jar. Я сбрасывал потоки 5 раз за 20-секундный интервал времени (общее время задержки) и каждый раз получал следующий результат:

"http-8080-exec-6" daemon prio=6 tid=0x65cae800 nid=0x1a50 runnable [0x67a3d000]
   java.lang.Thread.State: RUNNABLE
    at java.util.zip.ZipFile.open(Native Method)
    at java.util.zip.ZipFile.<init>(Unknown Source)
    at java.util.jar.JarFile.<init>(Unknown Source)
    at java.util.jar.JarFile.<init>(Unknown Source)
    at org.apache.catalina.loader.WebappClassLoader.openJARs(WebappClassLoader.java:2704)
    at org.apache.catalina.loader.WebappClassLoader.findResourceInternal(WebappClassLoader.java:2945)
    - locked <0x1804cc18> (a [Ljava.util.jar.JarFile;)
    at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2739)
    at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1144)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1639)
    - locked <0x1803dd38> (a org.apache.catalina.loader.WebappClassLoader)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1517)
    at java.beans.Introspector.instantiate(Unknown Source)
    at java.beans.Introspector.findExplicitBeanInfo(Unknown Source)
    - locked <0x434649a0> (a java.lang.Class for java.beans.Introspector)
    at java.beans.Introspector.<init>(Unknown Source)
    at java.beans.Introspector.getBeanInfo(Unknown Source)
    - locked <0x181bed70> (a java.lang.Object)

Я не могу не думать, но думаю, что существует какой-то кеш jar JRE / JVM, срок действия которого истекает через час и принудительное повторное сканирование файлов jar, но я не могу найти в Интернете ничего, что описывало бы такое поведение.

РЕДАКТИРОВАТЬ: Как оказалось, Tomcat WebappClassLoader кэширует файлы JAR и периодически очищает этот кеш. Теперь, чтобы узнать, можно ли каким-либо образом настроить этот кеш ...

РЕДАКТИРОВАТЬ: Tomcat закрывает все файлы JAR через 90 секунд после последнего обращения к файлу JAR. Я перезаписал WebappClassLoader , чтобы распечатать, когда файлы jar были закрыты. После закрытия файлов jar я попытался воспроизвести задержку, но не смог. Таким образом, это говорит мне, что существует либо кеш файлов JRE / JVM jar, либо просто что-то присущее операционной системе (или моей машине, антивирусу и т. Д.), Что вызывает медленную загрузку после долгой задержки. Все еще работаем над этим ...

5
задан Mark Watson 19 November 2010 в 16:12
поделиться