logo

Come funziona JVM: architettura JVM

Java Virtual Machine (JVM) è un componente principale di Java Runtime Environment (JRE) che consente ai programmi Java di essere eseguiti su qualsiasi piattaforma senza modifiche. JVM funge da interprete tra il bytecode Java e l'hardware sottostante fornendo la famosa funzionalità WORA (Write Once Run Anywhere) di Java.

  • Sorgente Java (.java) -> compilato da javac -> bytecode (.class)
  • JVM carica il bytecode, verifica che lo colleghi e quindi lo esegue
  • L'esecuzione può comportare l'interpretazione del bytecode o l'utilizzo della compilazione Just-In-Time (JIT) per convertire l'hot code in codice macchina nativo per le prestazioni
  • La Garbage Collection viene eseguita in background per recuperare memoria dagli oggetti inutilizzati

Architettura della JVM

L'immagine seguente mostra l'architettura e i componenti chiave di JVM.

Jvm' title=

Componenti dell'architettura JVM

Ora discuteremo in dettaglio ogni componente della JVM.



1. Sottosistema caricatore di classi

È principalmente responsabile di tre attività. 

class_loader_subsystem' loading='lazy' title=

1. Caricamento

  • Legge i file .class e memorizza i metadati della classe nell'area dei metodi.
  • Crea un oggetto Class nell'heap che rappresenta la classe caricata.
Java
class GFG{    static{    System.out.println('GFG class is loaded by the JVM!');  }  public void display(){    System.out.println('Method of GFG class is executed.');  } } public class Test{  public static void main(String[] args) throws Exception{    System.out.println('Main method started.');  // Loading the class explicitly using Class.forName()  Class.forName('GFG');  System.out.println('Class loaded successfully.');  // Creating object to execute method  GFG obj = new GFG();  obj.display();  } } 

Produzione
Main method started. GFG class is loaded by the JVM! Class loaded successfully. Method of GFG class is executed. 

Nota: Per ogni carico .classe solo file uno viene creato l'oggetto della classe.

2. Collegamento: Responsabile della preparazione della classe caricata per l'esecuzione. Comprende tre passaggi:

  • Verifica: Garantisce che il bytecode segua le regole JVM e sia sicuro da eseguire.
  • Preparazione: Alloca memoria per variabili statiche e assegna valori predefiniti.
  • Risoluzione: Converte i riferimenti simbolici in riferimenti diretti in memoria.

3. Inizializzazione

  • Assegna valori effettivi a variabili statiche.
  • Esegue i blocchi statici definiti nella classe.

Tipi di caricatore di classi

  • Caricatore di classi Bootstrap: Carica le classi Java principali (JAVA_HOME/lib).
  • Caricatore di classi di estensione: Carica le classi dalla directory delle estensioni (JAVA_HOME/jre/lib/ext).
  • Caricatore classi di sistema/applicazione: Carica le classi dal percorso classi dell'applicazione.
Java
// Java code to demonstrate Class Loader subsystem public class Geeks  {  public static void main(String[] args)  {  // String class is loaded by bootstrap loader and  // bootstrap loader is not Java object hence null  System.out.println(String.class.getClassLoader());  // Test class is loaded by Application loader  System.out.println(Geeks.class.getClassLoader());  } } 

Produzione
null jdk.internal.loader.ClassLoaders$AppClassLoader@8bcc55f 

2. Aree di memoria JVM

  • Area del metodo: Memorizza informazioni a livello di classe come nome della classe, metodi della classe genitore, variabili e dati statici. Condiviso attraverso la JVM.
  • Area dell'heap: Memorizza tutti gli oggetti. Condiviso attraverso la JVM.
  • Area della pila: Ogni thread ha il proprio stack di runtime; Il metodo Store chiama variabili locali negli stack frame. Distrutto quando il thread finisce.
  • Registri PC: Conserva l'indirizzo dell'istruzione attualmente in esecuzione per ciascun thread.
  • Stack di metodi nativi: Ogni thread ha uno stack separato per l'esecuzione del metodo nativo.

3. Motore di esecuzione 

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

  • Interprete: Interpreta il bytecode riga per riga e quindi lo esegue. Lo svantaggio qui è che quando un metodo viene chiamato più volte ogni volta è richiesta l'interpretazione.
  • Compilatore Just-In-Time (JIT): Viene utilizzato per aumentare l'efficienza di un interprete. Compila l'intero bytecode e lo modifica in codice nativo, quindi ogni volta che l'interprete vede chiamate di metodo ripetute, JIT fornisce codice nativo diretto per quella parte, quindi non è necessaria la reinterpretazione, quindi l'efficienza viene migliorata.
  • Raccoglitore di rifiuti: Distrugge gli oggetti senza riferimenti. Per ulteriori informazioni su Garbage Collector fare riferimento Raccoglitore di rifiuti .

4. Interfaccia nativa Java (JNI)

È un'interfaccia che interagisce con le librerie di metodi nativi e fornisce le librerie native (C C++) necessarie per l'esecuzione. Consente alla JVM di chiamare librerie C/C++ e di essere chiamata da librerie C/C++ che potrebbero essere specifiche dell'hardware.

5. Librerie di metodi nativi

Si tratta di raccolte di librerie native necessarie per l'esecuzione di metodi nativi. Includono librerie scritte in linguaggi come C e C++.