Sto utilizzando una libreria di terze parti che crea dinamicamente istanze di classi Java e popola tali istanze con l'aiuto di Introspector.getBeanInfo
. Alcune richieste possono comportare 5 o 6 chiamate successive a Introspector.getBeanInfo
. Ho scoperto che quando l'applicazione è inattiva per circa un'ora circa, la prima chiamata a Introspector.getBeanInfo
richiede un tempo significativamente più lungo per l'esecuzione (20-60 secondi) rispetto alle chiamate successive (< 100 millisecondi). Le chiamate effettuate nei prossimi minuti continuano a prendere < 100 millisecondi, ma quando aspetto un'altra ora, la prima chiamata riprende tra 20 e 60 secondi.Problemi di prestazioni durante la chiamata java.beans.Introspector.getBeanInfo dopo inattività
Nel tentativo di ricreare il comportamento con una semplice applicazione di test, ho riscontrato un comportamento simile quando un'applicazione Java non viene eseguita per un'ora. Ad esempio, se eseguo la seguente app console, potrebbero essere necessari 15 millisecondi. Se poi aspetto un'ora e rieseguo l'applicazione, sono necessari 20 secondi.
long start = System.currentTimeMillis();
System.out.println("Start");
Introspector.getBeanInfo(MyClass.class, Object.class);
long end = System.currentTimeMillis();
System.out.println("End: " + (end-start));
ho inizialmente pensato che il problema potrebbe essere legato al fatto che i tentativi di classe Introspector di creare istanze di classi sulla base di convenzioni di denominazione standard che non esistono nella mia applicazione (ad esempio, MyClassBeanInfo
), ed è stato impiegare molto tempo per scansionare i file jar nel tentativo di trovare quelle classi (la mia applicazione java ha poco più di 100 file jar di riferimento), ma ho chiamato Introspector.getBeanInfo(MyClass.class, Object.class, Introspector.IGNORE_ALL_BEANINFO)
usando il reflection (è un metodo privato in Sun's JRE che guardando il il codice sembra saltare la ricerca delle classi BeanInfo), e sono ancora in grado di riprodurre il ritardo.
Ho anche cercato informazioni riguardanti qualsiasi tipo di cache jar JRE/JVM, ma non ho ancora trovato nulla che sembra spiegare questo comportamento. Qualcuno ha idea del perché questo si comporta come fa e se c'è qualcosa che posso fare per risolverlo?
Come nota a margine sto usando JDK 1.6.0_21 su Windows XP. La libreria di terze parti che sto utilizzando è BlazeDS. La mia applicazione è ospitata in Tomcat utilizzando l'integrazione Spring/BlazeDS. Ho sovrascritto un certo numero di classi BlazeDS per individuare esattamente dove si trovava il ritardo (che è la chiamata a Introspector.getBeanInfo
nel metodo getPropertyDescriptorCacheEntry
di flex.messaging.io.BeanProxy
). Inoltre, BlazeDS memorizza nella cache BeanInfo, quindi le chiamate a Introspector.getBeanInfo
vengono eseguite solo quando Blaze deserializza un oggetto mappato su una classe Java che deve ancora essere elaborata. Quindi, ho altri modi per ovviare a questo problema, ma mi piacerebbe davvero sapere se esiste una spiegazione valida per questo comportamento.
MODIFICA: Ho eseguito jstack sul processo più volte durante la riproduzione del problema (grazie a @Tom) e ho confermato che è correlato al caricamento dei file jar. Buttai i fili 5 volte 20 secondi di tempo (tempo totale di ritardo) e ogni volta prodotto il seguente risultato:
"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)
non posso fare a meno che ci sia un qualche tipo di JRE/vaso JVM cache che scade dopo un'ora e costringendo i file jar a essere riesaminati, ma non riesco a trovare nulla online che delinea un simile comportamento.
MODIFICA: Come risulta il Tomcat WebappClassLoader
memorizza nella cache i file JAR e periodicamente elimina tale cache. Ora per scoprire se la cache è configurabile in ogni caso ...
MODIFICA: Tomcat chiude tutti i file JAR 90 secondi dopo l'ultima volta che è stato effettuato l'accesso a un file jar. Ho sovrascritto lo WebappClassLoader
per stampare quando i file jar sono stati chiusi. Dopo che i file jar sono stati chiusi, ho provato a riprodurre il ritardo, ma non ci sono riuscito.Quindi, questo mi dice che c'è una cache di file jar JRE/JVM, o solo qualcosa inerente al sistema operativo (o alla mia macchina, antivirus, ecc.) Che causa tempi di caricamento lenti dopo un lungo ritardo. Ci sto ancora lavorando ...
Si potrebbe provare a utilizzare 'jstack' o simile per vedere dove è arrivato il programma. Inoltre, qualsiasi connessione di rete coinvolti? –
il tuo profiler yourkit può salvare la tua giornata ... guardando il sole il codice java va bene e puoi imparare cose interessanti ma ci vuole troppo tempo. –
Grazie a @Tom - Vedi le modifiche sopra dopo aver eseguito jstack –