De Java Virtual Machine (JVM) is een kerncomponent van de Java Runtime Environment (JRE) waarmee Java-programma's zonder aanpassingen op elk platform kunnen worden uitgevoerd. JVM fungeert als tolk tussen Java-bytecode en de onderliggende hardware en biedt Java's beroemde Write Once Run Anywhere (WORA) -mogelijkheid.
- Java-bron (.java) -> gecompileerd door javac -> bytecode (.class)
- JVM laadt de bytecode, verifieert dat deze is gekoppeld en voert deze vervolgens uit
- Bij de uitvoering kan het gaan om het interpreteren van bytecode of het gebruik van Just-In-Time (JIT)-compilatie om hotcode om te zetten in native machinecode voor betere prestaties
- Garbage collection wordt op de achtergrond uitgevoerd om geheugen vrij te maken van ongebruikte objecten
Architectuur van JVM
De onderstaande afbeelding toont de architectuur en de belangrijkste componenten van JVM.
Componenten van JVM-architectuur
Nu gaan we elk onderdeel van de JVM in detail bespreken.
1. Subsysteem klasselader
Het is hoofdzakelijk verantwoordelijk voor drie activiteiten.
1. Laden
- Leest .class-bestanden en slaat klasse-metagegevens op in het Method Area.
- Creëert een Class-object in de heap die de geladen klasse vertegenwoordigt.
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(); } }
Uitvoer
Main method started. GFG class is loaded by the JVM! Class loaded successfully. Method of GFG class is executed.
Opmerking: Voor elke geladen .klas alleen bestand een object van de klasse wordt gemaakt.
2. Koppelen: Verantwoordelijk voor het gereedmaken van de geladen klasse voor uitvoering. Het omvat drie stappen:
- Verificatie: Zorgt ervoor dat de bytecode de JVM-regels volgt en veilig kan worden uitgevoerd.
- Voorbereiding: Wijst geheugen toe voor statische variabelen en wijst standaardwaarden toe.
- Oplossing: Converteert symbolische verwijzingen naar directe verwijzingen in het geheugen.
3. Initialisatie
- Wijst werkelijke waarden toe aan statische variabelen.
- Voert statische blokken uit die in de klasse zijn gedefinieerd.
Typen klasseladers
- Bootstrap-klasselader: Laadt kern-Java-klassen (JAVA_HOME/lib).
- Uitbreidingsklasselader: Laadt klassen uit de extensiemap (JAVA_HOME/jre/lib/ext).
- Systeem-/applicatieklasselader: Laadt klassen uit het klassenpad van de toepassing.
// 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()); } }
Uitvoer
null jdk.internal.loader.ClassLoaders$AppClassLoader@8bcc55f
2. JVM-geheugengebieden
- Methodegebied: Slaat informatie op klasseniveau op, zoals klassennaam, variabelen van klassenmethoden en statische gegevens. Gedeeld binnen de JVM.
- Hoopgebied: Slaat alle objecten op. Gedeeld binnen de JVM.
- Stapelgebied: Elke thread heeft zijn eigen runtime-stack; slaat de methode op die lokale variabelen in stapelframes aanroept. Vernietigd wanneer de draad eindigt.
- PC-registraties: Bewaar het adres van de momenteel uitgevoerde instructie voor elke thread.
- Native methodestapels: Elke thread heeft een afzonderlijke stapel voor de uitvoering van native methoden.
3. Uitvoeringsengine
Uitvoeringsengine voert de .class (bytecode) uit. Het leest de bytecode regel voor regel, gebruikt gegevens en informatie die aanwezig zijn in verschillende geheugengebieden en voert instructies uit. Het kan in drie delen worden ingedeeld:
- Tolk: Het interpreteert de bytecode regel voor regel en voert het vervolgens uit. Het nadeel hiervan is dat wanneer een methode meerdere keren wordt aangeroepen, elke keer dat interpretatie vereist is.
- Just-In-Time-compiler (JIT): Het wordt gebruikt om de efficiëntie van een tolk te vergroten. Het compileert de volledige bytecode en verandert deze in native code, dus telkens wanneer de tolk herhaalde methodeaanroepen ziet, levert JIT directe native code voor dat deel, zodat herinterpretatie niet vereist is en de efficiëntie wordt verbeterd.
- Afvalverzamelaar: Het vernietigt objecten waarnaar niet wordt verwezen. Voor meer informatie over Garbage Collector, zie Afvalverzamelaar .
4. Java-native interface (JNI)
Het is een interface die samenwerkt met de Native Method Libraries en de native bibliotheken (C C++) levert die nodig zijn voor de uitvoering. Het stelt JVM in staat C/C++-bibliotheken aan te roepen en te worden aangeroepen door C/C++-bibliotheken die specifiek kunnen zijn voor hardware.
5. Bibliotheken van native methoden
Dit zijn verzamelingen native bibliotheken die nodig zijn voor het uitvoeren van native methoden. Ze omvatten bibliotheken die zijn geschreven in talen als C en C++.