JVM (Java Virtual Machine) agisce come un motore di run-time per eseguire applicazioni Java. La JVM è quella che chiama effettivamente il metodo principale presente in un codice java. JVM è una parte di JRE (Java Runtime Environment).

Le applicazioni Java sono chiamate WORA (Write Once Run Anywhere). Questo significa che un programmatore può sviluppare il codice Java su un sistema e può aspettarsi che venga eseguito su qualsiasi altro sistema abilitato Java senza alcuna modifica. Tutto questo è possibile grazie alla JVM.

Quando compiliamo un file .java, i file .class (contenenti codice byte) con gli stessi nomi di classe presenti nel file .java sono generati dal compilatore Java. Questo file .class va in vari passi quando lo eseguiamo. Questi passi insieme descrivono l’intera JVM.

jvm

Sottosistema Class Loader

È principalmente responsabile di tre attività.

  • Caricamento
  • Collegamento
  • Inizializzazione

Caricamento: Il Class loader legge il file “.class”, genera i dati binari corrispondenti e li salva nell’area del metodo. Per ogni file “.class”, la JVM memorizza le seguenti informazioni nell’area del metodo.

  • Il nome pienamente qualificato della classe caricata e la sua classe madre immediata.
  • Se il file “.class” è relativo a Classe o Interfaccia o Enum.
  • Informazioni su modificatori, variabili e metodi ecc.

Dopo aver caricato il file “.class”, la JVM crea un oggetto di tipo Class per rappresentare questo file nella memoria heap. Si prega di notare che questo oggetto è di tipo Class predefinito nel pacchetto java.lang. Questi oggetti Class possono essere usati dal programmatore per ottenere informazioni a livello di classe come il nome della classe, il nome del genitore, i metodi e le informazioni variabili ecc. Per ottenere questo riferimento all’oggetto possiamo usare il metodo getClass() della classe Object.

Java

importjava.lang.reflect.Field;
importjava.lang.reflect.Method;
publicclassTest {

publicstaticvoidmain(String args)
{
Student s1 = newStudent();

Class c1 = s1.getClass();
System.out.println(c1.getName());
Method m = c1.getDeclaredMethods();
for(Method method : m)
System.out.println(method.getName());

Field f = c1.getDeclaredFields();
for(Field field : f)
System.out.println(field.getName());
}
}
classStudent {
privateString name;
privateintroll_No;
publicString getName() { returnname; }
public

voidsetName(String name) { this.name = name; }
publicintgetRoll_no() { returnroll_No; }
publicvoidsetRoll_no(introll_no)
{

this.roll_No = roll_no;
}
}



Output

StudentgetNamesetNamegetRoll_nosetRoll_nonameroll_No

Nota: Per ogni file “.class”, viene creato un solo oggetto della classe.

Student s2 = new Student();// c2 will point to same object where // c1 is pointingClass c2 = s2.getClass();System.out.println(c1==c2); // true

Linking: Esegue la verifica, la preparazione e (opzionalmente) la risoluzione.

  • Verifica: Assicura la correttezza del file .class, cioè controlla se questo file è formattato correttamente e generato da un compilatore valido o meno. Se la verifica fallisce, otteniamo un’eccezione run-time java.lang.VerifyError. Questa attività è fatta dal componente ByteCodeVerifier. Una volta che questa attività è completata, il file di classe è pronto per la compilazione.
  • Preparazione: La JVM alloca la memoria per le variabili di classe e la inizializza ai valori di default.
  • Risoluzione: È il processo di sostituzione dei riferimenti simbolici del tipo con riferimenti diretti. Viene fatto cercando nell’area del metodo per individuare l’entità referenziata.

Inizializzazione: In questa fase, tutte le variabili statiche sono assegnate con i loro valori definiti nel codice e nel blocco statico (se presente). Questo viene eseguito dall’alto verso il basso in una classe e dal genitore al figlio nella gerarchia della classe.
In generale, ci sono tre caricatori di classe:

  • Bootstrap class loader: Ogni implementazione JVM deve avere un caricatore di classi di bootstrap, capace di caricare classi affidabili. Carica le classi API di base di Java presenti nella directory “JAVA_HOME/jre/lib”. Questo percorso è popolarmente noto come percorso di avvio. È implementato in linguaggi nativi come C, C++.
  • Caricatore di classi di estensione: È un figlio del caricatore di classi di bootstrap. Carica le classi presenti nelle directory di estensione “JAVA_HOME/jre/lib/ext” (percorso di estensione) o qualsiasi altra directory specificata dalla proprietà di sistema java.ext.dirs. È implementato in java dalla classe sun.misc.Launcher$ExtClassLoader.
  • Caricatore di classi di sistema/applicazione: È un figlio del caricatore di classi di estensione. È responsabile del caricamento delle classi dal classpath dell’applicazione. Utilizza internamente la variabile d’ambiente che è mappata in java.class.path. È anche implementato in Java dalla classe sun.misc.Launcher$AppClassLoader.

public

classTest {
publicstaticvoidmain(String args)

{
System.out.println(String.class.getClassLoader());

System.out.println(Test.class.getClassLoader());
}
}



Output

nulljdk.internal.loader.ClassLoaders$AppClassLoader@8bcc55f

Nota: La JVM segue il principio di delegazione-gerarchia per caricare le classi. Il caricatore di classi di sistema delega la richiesta di carico al caricatore di classi di estensione e il caricatore di classi di estensione delega la richiesta al caricatore di classi di bootstrap. Se si trova una classe nel percorso di bootstrap, la classe viene caricata altrimenti la richiesta viene trasferita nuovamente al caricatore di classi di estensione e poi al caricatore di classi di sistema. Infine, se il caricatore di classe di sistema non riesce a caricare la classe, allora otteniamo l’eccezione di run-time java.lang.ClassNotFoundException.

jvm

Memoria JVM

  1. Area metodi: Nell’area del metodo, tutte le informazioni a livello di classe come il nome della classe, il nome della classe madre immediata, i metodi e le informazioni sulle variabili ecc. sono memorizzate, incluse le variabili statiche. C’è solo un’area metodi per JVM, ed è una risorsa condivisa.
  2. Area Heap: Le informazioni di tutti gli oggetti sono memorizzate nell’area heap. C’è anche un’area heap per JVM. Anche questa è una risorsa condivisa.
  3. Area stack: Per ogni thread, la JVM crea uno stack di run-time che viene memorizzato qui. Ogni blocco di questo stack è chiamato record di attivazione/stack frame che memorizza le chiamate ai metodi. Tutte le variabili locali di quel metodo sono memorizzate nel loro frame corrispondente. Dopo che un thread termina, il suo stack run-time sarà distrutto dalla JVM. Non è una risorsa condivisa.
  4. Registri PC: Memorizza l’indirizzo dell’istruzione di esecuzione corrente di un thread. Ovviamente, ogni thread ha registri PC separati.
  5. Stack dei metodi nativi: Per ogni thread, viene creato uno stack nativo separato. Memorizza le informazioni sui metodi nativi.

jvm2

Motore di esecuzione

Il motore di esecuzione esegue il “.class” (bytecode). Legge il codice byte riga per riga, utilizza i dati e le informazioni presenti in varie aree di memoria ed esegue le istruzioni. Può essere classificato in tre parti:

  • Interprete: Interpreta il bytecode riga per riga e poi lo esegue. Lo svantaggio qui è che quando un metodo è chiamato più volte, ogni volta è richiesta l’interpretazione.
  • Compilatore Just-In-Time (JIT): è usato per aumentare l’efficienza di un interprete. Compila l’intero bytecode e lo cambia in codice nativo, così ogni volta che l’interprete vede chiamate di metodi ripetute, JIT fornisce direttamente il codice nativo per quella parte, così la reinterpretazione non è richiesta, quindi l’efficienza è migliorata.
  • Garbage Collector: Distrugge gli oggetti non referenziati. Per ulteriori informazioni sul Garbage Collector, fare riferimento a Garbage Collector.

Java Native Interface (JNI) :

È un’interfaccia che interagisce con le librerie di metodi nativi e fornisce le librerie native (C, C++) necessarie per l’esecuzione. Permette alla JVM di chiamare le librerie C/C++ e di essere chiamata dalle librerie C/C++ che possono essere specifiche per l’hardware.

Le librerie di metodi nativi:

È una collezione di librerie native (C, C++) che sono richieste dal motore di esecuzione.
Questo articolo è stato contribuito da Gaurav Miglani. Se ti piace GeeksforGeeks e vuoi contribuire, puoi anche scrivere un articolo usando contribute.geeksforgeeks.org o inviare il tuo articolo a [email protected]. Vedi il tuo articolo apparire sulla pagina principale di GeeksforGeeks e aiuta altri Geeks.
Si prega di scrivere commenti se trovi qualcosa di errato, o se vuoi condividere ulteriori informazioni sull’argomento trattato sopra.

Tag dell’articolo :

Java

Practice Tags :

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *