Ich verwende eine 3rd-Party-Bibliothek, die dynamisch Instanzen von Java-Klassen erstellt und diese Instanzen mit Hilfe von Introspector.getBeanInfo
füllt. Bestimmte Anforderungen können zu 5 oder 6 aufeinanderfolgenden Aufrufen an Introspector.getBeanInfo
führen. Ich habe herausgefunden, dass, wenn die Anwendung für ungefähr eine Stunde oder so im Leerlauf ist, der erste Anruf zu Introspector.getBeanInfo
eine wesentlich viel längere Zeit dauert (20-60 Sekunden) als die nachfolgenden Anrufe (< 100 Millisekunden). Anrufe, die innerhalb der nächsten Minuten gemacht werden, dauern weiterhin 100 Millisekunden, aber wenn ich eine weitere Stunde warte, dauert der erste Anruf erneut 20-60 Sekunden.Leistungsprobleme beim Aufruf von java.beans.Introspector.getBeanInfo nach Inaktivität
In einem Versuch, das Verhalten mit einer einfachen Testanwendung neu zu erstellen, habe ich ähnliches Verhalten gefunden, wenn eine Java-Anwendung selbst für eine Stunde nicht ausgeführt wird. Wenn ich zum Beispiel die folgende Konsolenanwendung verwende, kann es 15 Millisekunden dauern. Wenn ich dann eine Stunde warte und die Anwendung erneut starte, dauert es 20 Sekunden.
long start = System.currentTimeMillis();
System.out.println("Start");
Introspector.getBeanInfo(MyClass.class, Object.class);
long end = System.currentTimeMillis();
System.out.println("End: " + (end-start));
Ich dachte ursprünglich das Problem auf die Tatsache zurückzuführen sein, dass die Introspector Klasse Versucht Instanzen von Klassen auf Basis von Standard-Namenskonventionen zu erstellen, die in meiner Anwendung nicht existieren (zum Beispiel MyClassBeanInfo
), und es war Es dauert sehr lange, die JAR-Dateien zu scannen, um diese Klassen zu finden (meine Java-Anwendung hat etwas mehr als 100 referenzierte JAR-Dateien), aber ich habe Introspector.getBeanInfo(MyClass.class, Object.class, Introspector.IGNORE_ALL_BEANINFO)
mit Reflektion aufgerufen (es handelt sich um eine private Methode in Suns JRE) Code scheint das Nachschlagen der BeanInfo-Klassen zu überspringen, und ich konnte die Verzögerung noch reproduzieren.
Ich habe auch nach Informationen über jede Art von JRE/JVM Jar-Cache gesucht, aber habe noch nichts gefunden, was dieses Verhalten zu erklären scheint. Jeder weiß, warum sich das so verhält und ob ich etwas dagegen tun kann.
Als Randnotiz verwende ich JDK 1.6.0_21 unter Windows XP. Die 3rd-Party-Bibliothek, die ich verwende, ist BlazeDS. Meine Anwendung wird in Tomcat mit Spring/BlazeDS-Integration gehostet. Ich überschrieb eine Anzahl von BlazeDS-Klassen, um genau festzustellen, wo die Verzögerung war (das ist der Aufruf an Introspector.getBeanInfo
in der getPropertyDescriptorCacheEntry
Methode von flex.messaging.io.BeanProxy
). Außerdem speichert BlazeDS die BeanInfo, daher werden Aufrufe an Introspector.getBeanInfo
nur vorgenommen, wenn Blaze ein Objekt deserialisiert, das einer Java-Klasse zugeordnet ist, die noch verarbeitet werden muss. Daher habe ich andere Möglichkeiten, um dieses Problem zu umgehen, aber ich würde gerne wissen, ob es eine gültige Erklärung für dieses Verhalten gibt.
EDIT: Ich lief jstack auf dem Prozess mehrmals während der Wiedergabe des Problems (danke @ Tom) und hat bestätigt, dass es im Zusammenhang mit dem Laden von JAR-Dateien. Ich warf die Fäden 5-mal über einen 20 Sekunden Zeitrahmen (Gesamtzeit der Verzögerung) und jedes Mal das folgende Ergebnis:
"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)
ich nicht helfen, aber denke, es ist eine Art von JRE/JVM jar Cache, der nach einer Stunde abläuft und die JAR-Dateien zum erneuten Scannen zwingt, aber ich kann nichts online finden, das dieses Verhalten umreißt.
EDIT: Wie sich herausstellt, speichert der Tomcat WebappClassLoader
JAR-Dateien und löscht diesen Cache regelmäßig. Jetzt um herauszufinden, ob dieser Cache konfigurierbar ist in jedem Fall ...
EDIT: Tomcat schließt alle JAR-Dateien 90 Sekunden nach dem letzten Zugriff auf eine JAR-Datei. Ich überschrieb die WebappClassLoader
, um auszudrucken, wenn die JAR-Dateien geschlossen wurden. Nachdem die JAR-Dateien geschlossen wurden, versuchte ich die Verzögerung zu reproduzieren, konnte dies aber nicht.Das bedeutet, dass entweder ein JRE/JVM-JAR-Dateicache oder nur etwas, das dem Betriebssystem (oder meinem Computer, Antivirenprogramm usw.) inhärent ist, zu langsamen Ladezeiten nach einer langen Verzögerung führt. Arbeitet noch daran ...
Sie könnten versuchen, 'jstack' oder ähnliches zu verwenden, um zu sehen, wo das Programm hinkommt. Auch jede Netzwerkverbindung beteiligt? –
yourkit Profiler kann Ihren Tag speichern .. in der Sonne schauen Java-Code ist in Ordnung, und Sie können interessante Dinge lernen, aber es dauert viel zu viel Zeit. –
Danke @Tom - Siehe Änderungen nach dem Ausführen von jstack –