J'utilise une bibliothèque tierce qui crée dynamiquement des instances de classes Java et les remplit à l'aide de Introspector.getBeanInfo
. Certaines demandes peuvent entraîner 5 ou 6 appels successifs à Introspector.getBeanInfo
. J'ai trouvé que lorsque l'application est inactive pendant environ une heure ou deux, le premier appel à Introspector.getBeanInfo
prend beaucoup plus de temps à exécuter (20-60 secondes) par rapport aux appels suivants (< 100 millisecondes). Les appels effectués dans les prochaines minutes continuent à prendre < 100 millisecondes, mais quand j'attends encore une heure, le premier appel prend encore 20-60 secondes.Problèmes de performances lors de l'appel de java.beans.Introspector.getBeanInfo après l'inactivité
Dans une tentative de recréer le comportement avec une application de test simple, j'ai trouvé un comportement similaire lorsqu'une application Java elle-même n'est pas exécutée pendant une heure. Par exemple, si j'exécute l'application de console suivante, cela peut prendre 15 millisecondes. Si j'attends une heure et réexécute l'application, il faut 20 secondes pour terminer.
long start = System.currentTimeMillis();
System.out.println("Start");
Introspector.getBeanInfo(MyClass.class, Object.class);
long end = System.currentTimeMillis();
System.out.println("End: " + (end-start));
Je pensais à l'origine du problème peut être lié au fait que les tentatives de classe Introspector pour créer des instances de classes fondées sur les conventions de nommage standard qui n'existent pas dans mon application (par exemple, MyClassBeanInfo
), et il était Il faut beaucoup de temps pour analyser les fichiers jar afin de trouver ces classes (mon application java contient un peu plus de 100 fichiers jar référencés), mais j'ai appelé Introspector.getBeanInfo(MyClass.class, Object.class, Introspector.IGNORE_ALL_BEANINFO)
en utilisant la réflexion (c'est une méthode privée dans JRE de Sun le code semble ignorer la recherche des classes BeanInfo), et j'étais encore capable de reproduire le délai.
J'ai également recherché des informations concernant n'importe quel type de cache JAR JRE/JVM, mais je n'ai pas encore trouvé quelque chose qui semble expliquer ce comportement. Quelqu'un at-il la moindre idée de la raison pour laquelle cela se comporte ainsi, et s'il y a quelque chose que je peux faire pour le réparer?
En note, j'utilise JDK 1.6.0_21 sous Windows XP. La bibliothèque tierce que j'utilise est BlazeDS. Mon application est hébergée dans Tomcat en utilisant l'intégration Spring/BlazeDS. J'ai écrasé un certain nombre de classes BlazeDS afin de localiser exactement où le retard était (qui est l'appel à Introspector.getBeanInfo
dans la méthode getPropertyDescriptorCacheEntry
de flex.messaging.io.BeanProxy
). En outre, BlazeDS met en cache le BeanInfo, donc les appels à Introspector.getBeanInfo
ne sont effectués que lorsque Blaze désérialise un objet mappé à une classe Java qui n'a pas encore été traitée. Donc, j'ai d'autres façons de contourner ce problème, mais j'aimerais vraiment savoir s'il existe une explication valable pour ce comportement. J'ai exécuté jstack sur le processus plusieurs fois tout en reproduisant le problème (merci @Tom) et ai confirmé qu'il est lié au chargement des fichiers jar. Je jetai les fils 5 fois sur un châssis 20 deuxième fois (durée totale du retard) et à chaque fois produit le résultat suivant:
"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)
Je ne peux pas empêcher de penser qu'il ya une sorte de pot JRE/JVM cache qui expire après une heure et forçant les fichiers jar à être re-scannés, mais je ne trouve rien en ligne qui décrit un tel comportement. Comme il s'avère que le Tomcat WebappClassLoader
cache les fichiers JAR et purge périodiquement ce cache. Maintenant, pour savoir si ce cache est configurable de toute façon ...
EDIT: Tomcat ferme tous les fichiers JAR 90 secondes après le dernier accès à un fichier jar. J'ai écrasé WebappClassLoader
pour imprimer lorsque les fichiers jar ont été fermés. Après la fermeture des fichiers jar, j'ai essayé de reproduire le délai, mais je n'ai pas pu le faire.Donc, cela me dit qu'il y a un cache de fichier JAR JRE/JVM, ou juste quelque chose d'inhérent au système d'exploitation (ou ma machine, antivirus, etc) qui provoque des temps de chargement lent après un long délai. Toujours en train de travailler ...
Vous pourriez essayer d'utiliser 'jstack' ou similaire pour voir où le programme est arrivé. En outre, toute connexion réseau impliqué? –
Votre profileur profil peut sauver votre journée ... regarder dans le code java du soleil est très bien et vous pouvez apprendre des choses intéressantes, mais cela prend beaucoup trop de temps. –
Merci @Tom - Voir les modifications ci-dessus après l'exécution jstack –