MokaByte Numero 11 - Settembre 1997
  
Java Performance Runtime
per Windows
 
di
Donato Cappetta
Come eseguire le applicazioni Java in ambiente Windows installando solo il Runtime di Java

 


Un problema che si incontra sviluppando applicazioni Java è: come distribuire la propria applicazioni all'utente finale, che non ha una Java Virtual Machine installata.
Una soluzione, per l'ambiente Windows, arriva direttamente dalla Sun Microsystems con il Java Performance Runtime for Windows. Esso è l'insieme di due pacchetti: il Java Runtime Environment (JRE) che contiene il runtime di Java e il Java Performance Pack (JPP) che integra il JRE con un compilatore Just in Time (JIT).

La soluzione proposta si basa sul JDK1.1 ed è pienamente compatibile con esso. Al momento della scrittura dell'articolo è disponibile la versione 1.1.3 del JRE e del JPP che sono scaricabili separatamente dal sito della Sun http://java.sun.com/products/jdk/1.1. L'installazione dei due pacchetti deve essere effettuata separatamente per cui essi saranno analizzati separatamente.

Il Java Runtime Environment

Il JRE è disponibile oltre che per la piattaforma Win32 (Windows 95 e Windows NT 4.0, non è stato testato su Windows NT 3.51) anche per Solaris. Il JRE per Win32 (jre113.exe) è disponibile in due versioni:

Senza il supporto per l'internalizzazione (~2.5 MByte)
Con supporto per l'internalizzazione (~5.8 MByte)

Esso contiene la piattaforma minima Java per poter eseguire le applicazioni ovvero la macchina virtuale, il minimo delle classi java standard e dei file di supporto.
Scaricato il file (jre113.exe) l'installazione è relativamente semplice, con un doppio click su di esso va in esecuzione il setup-wizard che consente un'installazione guidata. Non ci sono molti parametri che possono essere impostati, l'unico che merita attenzione e il path in cui si installa il JRE. Per default il path è:

E' possibile specificare un path diverso in fase di installazione ed è consigliabile non modificarlo successivamente. Il JRE aggiunge delle chiavi al registro di configurazione di Windows in particolare la chiave

    HKEY_LOCAL_MACHINE\Software\JavaSoft\RunTime Environment\1.1\JavaHome

viene impostata in installazione con il path specificato.
In fase di esecuzione del JRE le classi e le DLL standard di Java vengono caricate rispettivamente dalla directory lib (file rt.jar)e dalla directory bin, a partire dal path specificato nella chiave JavaHome.In fase di installazione del JRE non vengono modificati altri parametri (non viene modificato l'Autoexec.bat né vengono settate variabili di ambiente).
Una copia dei file eseguibili (sono due: jre.exe e jrew.exe) viene installata automaticamente anche nella directory di Windows in modo che essi possono essere immediatamente richiamati essendo la directory di Windows inclusa per default nel path dei comandi.
Terminata l'installazione, l'interprete JRE può essere invocato dal prompt dei comandi usando il tool jre (o jrew), esso ignorerà la variabile di ambiente CLASSPATH (se definita). La Sun Microsystems raccomanda l'uso dell'opzione -cp per specificare il path delle classi dell'applicazione.
La sintassi del comando jre è la seguente:

Una versione alternativa a questo comando è il jrew, esso è identico al jre eccetto che non viene aperta una finestra Windows, la sintassi è analoga: dove: nomeclasse rappresenta il nome del file contenete la classe java e <argomenti> rappresenta eventuali argomenti che devono essere passati alla classe

Le opzioni ([opzioni])più significative sono:

Generalmente non si ha l'esigenza di usare l'opzione -classpath, mentre -cp diviene quasi obbligatorio, si consideri che jre.exe per default assume, come classpath, solo quello specificato nel registro di configurazione, quindi neanche la directory corrente fa parte del classpath. Per cui il comando più semplice per invocare il jre su di una classe e del tipo (si supponga di trovarsi nella directory in cui è contenuta la classe): l'uso del comando senza -cp . da un errore di "classe non trovata". Un errore non gestito, invece, è il caso in cui MyClass importi delle classi contenute in un package situato in una libreria di classi(file .zip o .jar) o in un'altra directory, allora il comando diviene del tipo (supponendo la libreria in C:\xyz\lib.zip): fin qui niente di nuovo; ma se il path della libreria non è corretto non si ha un messaggio di errore bensì l'oscuro messaggio di Windows: "Questo programma ha eseguito un'operazione non valida è sarà terminato" che fa pensare a chissà quale disastro; magari si è solo dimenticati di digitare il path della libreria.

Il comando jrew è analogo a jre, eccetto che jrew non è associato ad una console window. Si può usare jrew quando non si vuole che appaia il prompt dei comandi durante l'esecuzione delle applicazioni Java. Questo comando è utilizzabile per applicazioni con interfaccia grafica (in pratica applicazioni che fanno uso del package java.awt) in quanto i messaggi diretti allo standard output non vengono visualizzati, così come non vengono visualizzati i messaggi di errore generati dall'interprete. Con jrew è possibile, per esempio, creare un collegamento all'applicazione Java dal desktop di Windows. Specificando che deve essere invocato il comando jrew.exe e settando l'eventuale classpath (-cp), con un doppio click sull'icona creata va in esecuzione l'applicazione Java (con interfaccia grafica) senza che nessuna finestra supplementare venga aperta.

Il Java Performance Pack

Il JPP è disponibile solo per la piattaforma Win32. Esso fornisce un compilatore  Jist In Time1 (JIT) al JRE ma è possibile usarlo anche con il JDK 1.1.3! La Sun Microsystems dichiara un incremento di prestazioni, durante l'esecuzione di applet o applicazioni, di un fattore 10. La Sun precisa anche di non usare questo JIT per applicazioni mission-critical essendo questa tecnologia una versione preview.
Il file jpp113.exe, che si scarica dal sito web JavaSoft, è di ~800 kByte e si installa con estrema facilità. Prerequisito per l'installazione è che sulla propria macchina sia già installato il JRE 1.1.3 o il JDK 1.1.3. Accertato ciò, con un doppio click sul jpp113.exe va in esecuzione l'installazione, quasi trasparente, non essendoci nessun parametro da impostare. Terminata l'installazione il compilatore JIT (si tratta del file symcjit.dll) può essere usanto con il JRE o con il JDK.

Se il JPP e il JRE sono entrambi installati il compilatore JIT viene invocato per default quando va in esecuzione il programma jre.exe (o jrew.exe). Infatti durante l'installazione del jpp113.exe viene settata la chiave compiler del JRE nel registro di windows: per cui il JIT "symcjit" è il compilatore di default. Se si ha l'esigenza di usare l'interprete del JRE senza invocare il JIT basta specificare l'ozpione -nojit quando viene usato il comando jre.exe. Se si vuole usare il compilatore JIT con i tools java.exe, javac.exe e appletviewer.exe del JDK 1.1.3 allora si deve settare la variabile di ambiente JAVA_COMPILER al valore "symcjit". Ciò dal prompt dei comandi si deve usare la sintassi: quando questa variabile è settata, per default, usando i tools del JDK 1.1.3, viene invocato il compilatore JIT.
In alternativa è possibile invocare il compilatore JIT settando la proprietà java-compiler del JDK con il valore "symcjit". Questo dal prompt dei comandi nel seguente modo: per l'appletviewer e per il compilatore javac. Mentre per l'interprete java.exe la sintassi è la seguente: Se è stata settata la variabile d'ambiente JAVA_COMPILER e successivamente non si vuole più usare il compilatore JIT basta settare nuovamente JAVA_COMPILER a nessun valore, ovvero: Un pò di Test

Visto che lo scopo del Java Performance Runtime è di distribuire applicazioni Java può essere interessante analizzare come si comporta in termini di prestazioni; soprattutto per la presenza del compilatore JIT, perciò si vanno adesso ad eseguire alcuni test.
Si precisa che questi test vogliono dare solo un'idea generale delle prestazioni del JIT ma non sono assolutamente da considerarsi completi né tantomeno esaustivi!
Il confronto viene fatto in termini di tempo tra l'interprete java.exe (senza compilatore JIT) del JDK e l'interprete jre.exe con compilatore JIT.
I test vengono eseguiti considerando,per comodità e semplicità, i seguenti algoritmi: di ricorsione, di iterazione e di allocazione. Si precisa nuovamente che il test non è affatto da ritenersi rigoroso! Difficilmente i programmi reali si possono classificare così schematicamente.

L'algoritmo ricorsivo considerato è quello che genera il numero di Fibonacci, chi non sapesse cos'è tale numero non si preoccupi. Esso non ha molta utilità pratica, l'algoritmo è utile solo perchè genera una ricorsione ad albero, in pratica fa lavorare molto la macchina virtuale.
Quando il programma viene eseguito, dalla riga dei comandi, si fornisce un numero (intero) come argomento e ne viene calcolato il numero di Fibonacci. Il tempo misurato è solo quello relativo all'esecuzione della funzione che calcola il risultato, ed è espresso in millisecondi (ms).
Il test viene riassunto nella seguente tabella:
 
Numero in input  Tempo jre.exe
(con JIT) 
Tempo java.exe
(senza JIT) 
Rapporto fra i tempi
java/jre 
30 380 ms 2910 ms 7.66
32 980 ms 7281 ms 7.43
34 2520 ms 18680 ms 7.41
35 4120 ms 30776 ms 7.47
36 6650 ms 48611 ms 7.31
Tabella 1

Nell'ultima colonna della tabella viene riportato anche il rapporto tra i due tempi, in media l'interprete jre.exe è stato 7.4 volte più veloce dell'interprete java.exe.

L'algoritmo iterativo considerato è di ordinamento: il BubbleSort. Non è il miglior algoritmo di ordinamento, ma in questo caso ci è utile in quanto per ordinare itera più volte sulla lista (contiene due cicli for nidificati).
Quando il programma viene eseguito, dalla riga dei comandi, si fornisce come argomento il numero di elementi da ordinare, essi vengono generati in maniera casuale (random) e poi vengono passati all'algoritmo di ordinamento. Generare i numeri in modo random non è corretto perchè il test viene eseguito con sequenze sempre diverse tra loro, ma questo è trascurabile. Il tempo misurato è solo quello relativo all'ordinamento, ed è espresso in millisecondi (ms).
Il test viene riassunto nella seguente tabella:
 
Numero di elementi 
da ordinare
Tempo jre.exe
(con JIT) 
Tempo java.exe
(senza JIT) 
Rapporto fra i tempi
java/jre 
2000 270 ms 2750 ms 10.1
4000 1050 ms 10510 ms  10.0
6000 2360 ms  23620 ms 10.0
7000 3240 ms 32570 ms 10.0
8000 4220 ms 42290 ms 10.0
Tabella 2

In media l'interprete jre.exe è stato 10 volte più veloce dell'interprete java.exe.

L'ultimo test riguarda l'allocazione di memoria, in pratica lo scopo è di valutare quanto è più veloce un interprete con JIT quando ci sono delle new() da eseguire.
Il programma è molto semplice, quando viene eseguito, dalla prompt dei comandi, si fornisce come argomento un numero che rappresenta quanti oggetti di tipo Point() devono essere allocati (la scelta del tipo è stata fatta senza una logica particolare). Un ciclo for provvede all'operazione.Il tempo misurato è solo quello relativo all'allocazione, ed è espresso in millisecondi (ms).
Il test viene riassunto nella seguente tabella:
 
Numero di elementi 
da allocare
Tempo jre.exe
(con JIT) 
Tempo java.exe
(senza JIT) 
Rapporto fra i tempi
java/jre 
100.000 440 ms 880  ms 2.0
200.000 830 ms 1670 ms 2.0
300.000 1200 ms 2410 ms 2.0
400.000 1510 ms 3030 ms 2.0
500.000 2030 ms 4070 ms 2.0
Tabella 3

In media l'interprete jre.exe è stato 2 volte più veloce dell'interprete java.exe.

Quest'ultimo test dimostra che il compilatore JIT non è sempre performante. Del resto il risultato era prevedibile essendo la rappresentazione (runtime) degli oggetti in Java abbastanza complessa, per cui, in caso di allocazione, il compilatore JIT migliora relativamente le prestazioni.
Va comunque  rilevato che  quest'ultimo test è stato eseguito considerando un numero di allocazioni elevato (ordine 105) e i tempi sono di tutto rispetto, con e senza JIT.
In generale si può affermare che il compilatore JIT si è "comportato" bene.
Naturalmente per un giudizio complessivo occorrono test del tutto generali e più rigorosi.
I test sono stati eseguiti su un PC Pentium 133.

Conclusione

Spesso sulla mailing list java-it c'erano richieste di come distribuire le applicazioni Java, e quali file del JDK erano indispensabili. Il Java Performance Runtime risolve completamente il problema.
Adesso è disponibile per la piattaforma Windows (il JRE anche per Solaris), ma è probabile che in futuro saranno disponibili le versioni per le piattaforme più diffuse. L'installazione non presenta problemi, l'occupazione di spazio è ridotta, e il compilatore JIT fa la sua parte migliorando le prestazioni. Comodo è anche il tool jrew che consente di configurare l'esecuzione di una applicazione Java con il semplice click del mouse (creando un collegamento dal menu di Windows), rendendo, così, del tutto trasparente la presenza della macchina virtuale Java.

Donato Cappetta


(1) L'interprete Java, per ciascun bytecode, elobora una sequenza di istruzioni in codice nativo per la CPU hardware che sta utilizzando. Se si salva una copia di ciascuna istruzione binaria (codice nativo)così come viene eseguita, la volta successiva che lo stesso codice deve essere interpretato si può eseguire direttamente il codice binario memorizzato in precedenza, senza doverlo interpretare nuovamente, ottenendo così un notevole incremento di prestazioni. Questo processo è noto come "traduzione dinamica". La Sun lo ha chiamato "compilazione in tempo reale" (Just In Time).



 
 
  
 

MokaByte rivista web su Java

MokaByte ricerca nuovi collaboratori
Chi volesse mettersi in contatto con noi può farlo scrivendo a mokainfo@mokabyte.it