Używam biblioteki innej firmy, która dynamicznie tworzy wystąpienia klas Java i wypełnia te instancje za pomocą Introspector.getBeanInfo
. Niektóre żądania mogą skutkować 5 lub 6 kolejnymi połączeniami do Introspector.getBeanInfo
. Zauważyłem, że gdy aplikacja jest bezczynna przez około godzinę, pierwsze wywołanie Introspector.getBeanInfo
wymaga znacznie dłuższego czasu do wykonania (20-60 sekund) w porównaniu z kolejnymi połączeniami (< 100 milisekund). Połączenia wykonane w ciągu kilku następnych minut trwają przez cały czas <, ale kiedy poczekam na kolejną godzinę, pierwsze połączenie ponownie zajmie 20-60 sekund.Problemy z wydajnością podczas wywoływania java.beans.Introspector.getBeanInfo po nieaktywności
Próbując odtworzyć zachowanie za pomocą prostej aplikacji testowej, znalazłem podobne zachowanie, gdy sama aplikacja java nie jest uruchamiana przez godzinę. Na przykład, jeśli uruchomię poniższą aplikację konsoli, ukończenie jej może potrwać 15 milisekund. Jeśli następnie poczekam godzinę i ponownie uruchomę aplikację, jej ukończenie zajmie 20 sekund.
long start = System.currentTimeMillis();
System.out.println("Start");
Introspector.getBeanInfo(MyClass.class, Object.class);
long end = System.currentTimeMillis();
System.out.println("End: " + (end-start));
I początkowo myślałem że problem może być związany z faktem, że próby klasy Introspector tworzyć instancje klas opartych na standardowych konwencji nazewnictwa, które nie istnieją w mojej aplikacji (na przykład MyClassBeanInfo
), i było długo trwa skanowanie plików jar w celu znalezienia tych klas (moja aplikacja java ma niewiele ponad 100 odwołanych plików jar), ale nazwałem je Introspector.getBeanInfo(MyClass.class, Object.class, Introspector.IGNORE_ALL_BEANINFO)
za pomocą refleksji (jest to prywatna metoda w JRE firmy Sun, która od spojrzenia na kod wydaje się pomijać klasy BeanInfo), a ja wciąż mogłem odtworzyć opóźnienie.
Też szukałem informacji dotyczących każdego typu bufora JRE/JVM, ale jeszcze nie znalazłem niczego, co wydaje się wyjaśniać to zachowanie. Ktoś ma jakąś wskazówkę, dlaczego tak się zachowuje, i czy jest coś, co mogę zrobić, żeby to naprawić?
Na marginesie używam JDK 1.6.0_21 w systemie Windows XP. Używam biblioteki firm zewnętrznych BlazeDS. Moja aplikacja jest hostowana w Tomcat z wykorzystaniem integracji Spring/BlazeDS. Nadpisałem kilka klas BlazeDS, aby dokładnie określić, gdzie było opóźnienie (to jest połączenie z Introspector.getBeanInfo
w metodzie getPropertyDescriptorCacheEntry
z flex.messaging.io.BeanProxy
). BlazeDS buforuje również BeanInfo, więc wywołania do Introspector.getBeanInfo
są tworzone tylko wtedy, gdy Blaze deserializuje obiekt, który jest odwzorowany na klasę Java, która nie została jeszcze przetworzona. Tak, mam inne sposoby obejścia tego problemu, ale naprawdę chciałbym wiedzieć, czy istnieje uzasadnione wyjaśnienie tego zachowania.
EDYCJA: Uruchomiłem jstack w procesie wiele razy podczas odtwarzania problemu (dzięki @Tom) i potwierdziłem, że jest on związany z ładowaniem plików jar. Rzuciłam nitek 5 razy w ciągu 20 sekund przedziale czasowym (całkowity czas opóźnienia) i za każdym razem produkowane następujący wynik:
"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)
nie mogę pomóc, ale myślę, że jest jakiś rodzaj JRE/JVM słoiku pamięć podręczna wygasająca po godzinie i wymuszająca ponowne skanowanie plików JAR, ale nie mogę znaleźć niczego w Internecie, które nakreśla takie zachowanie.
EDYTOWANIE: Okazuje się, że Tomcat WebappClassLoader
buforuje pliki JAR i okresowo usuwa pamięć podręczną. Teraz, aby dowiedzieć się, czy pamięć podręczna jest konfigurowalna w każdym razie ...
EDYTOWANIE: Tomcat zamyka wszystkie pliki JAR 90 sekund po ostatnim dostępie do pliku jar. Nadpisałem numer WebappClassLoader
, aby wydrukować, gdy pliki JAR zostały zamknięte. Po zamknięciu plików JAR próbowałem odtworzyć opóźnienie, ale nie mogłem.Mówi mi to, że istnieje albo pamięć podręczna plików JRE/JVM, albo tylko coś związanego z systemem operacyjnym (lub moją maszyną, programem antywirusowym itp.), Które powoduje powolne czasy ładowania po długim opóźnieniu. Nadal nad nim pracuję ...
Możesz spróbować użyć 'jstack' lub podobnego, aby zobaczyć, gdzie program się dostał. Ponadto, jakiekolwiek połączenie sieciowe jest zaangażowane? –
profiler yourkit może uratować twój dzień .. patrząc na słońce kod java jest w porządku i możesz uczyć się ciekawych rzeczy, ale zajmuje to zbyt dużo czasu. –
Dzięki @Tom - Zobacz zmiany powyżej po uruchomieniu jstack –