JVM (Java Virtual Machine) fungeert als een run-time engine om Java applicaties te draaien. JVM is degene die in feite de hoofdmethode aanroept die aanwezig is in een java code. JVM is een onderdeel van JRE (Java Runtime Environment).
Java applicaties worden WORA (Write Once Run Anywhere) genoemd. Dit betekent dat een programmeur Java code kan ontwikkelen op een systeem en kan verwachten dat het op elk ander Java systeem draait zonder enige aanpassing. Dit is allemaal mogelijk dankzij JVM.
Wanneer we een .java bestand compileren, worden .class bestanden (bevat byte-code) met dezelfde class namen aanwezig in .java bestand gegenereerd door de Java compiler. Dit .class bestand doorloopt verschillende stappen wanneer we het uitvoeren. Deze stappen samen beschrijven de hele JVM.
Class Loader Subsystem
Het is hoofdzakelijk verantwoordelijk voor drie activiteiten.
- Loading
- Linking
- Initialization
Loading: De Class loader leest het “.class”-bestand, genereert de bijbehorende binaire gegevens en slaat deze op in het methodegebied. Voor elk “.class” bestand slaat de JVM de volgende informatie op in het methodegebied.
- De volledig gekwalificeerde naam van de geladen klasse en de directe bovenliggende klasse.
- Of het “.klasse” bestand is gerelateerd aan een Klasse of Interface of Enum.
- Modifier, Variabelen en Methode informatie etc.
Na het laden van het “.klasse” bestand, creëert JVM een object van het type Klasse om dit bestand in het heap geheugen te representeren. Dit object is van het type Class dat vooraf is gedefinieerd in het java.lang-pakket. Deze Klasse-objecten kunnen door de programmeur worden gebruikt om klasse-informatie te verkrijgen, zoals de naam van de klasse, de naam van de ouder, methodes en variabele informatie enz. Om deze objectverwijzing te krijgen kunnen we de methode getClass() van de klasse Object gebruiken.
import
java.lang.reflect.Field;
import
java.lang.reflect.Method;
public
class
Test {
public
static
void
main(String args)
{
Student s1 =
new
Student();
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());
}
}
class
Student {
private
String name;
private
int
roll_No;
public
String getName() {
return
name; }
public
void
setName(String name) {
this
.name = name; }
public
int
getRoll_no() {
return
roll_No; }
public
void
setRoll_no(
int
roll_no)
{
this
.roll_No = roll_no;
}
}
Uitvoer
StudentgetNamesetNamegetRoll_nosetRoll_nonameroll_No
Note: Voor elk geladen “.class” bestand wordt slechts één object van de class aangemaakt.
Student s2 = new Student();// c2 will point to same object where // c1 is pointingClass c2 = s2.getClass();System.out.println(c1==c2); // true
Koppelen: Voert verificatie, voorbereiding, en (optioneel) resolutie uit.
- Verificatie: Het verzekert de juistheid van het .class bestand, d.w.z. het controleert of dit bestand juist is geformatteerd en gegenereerd door een geldige compiler of niet. Als de verificatie mislukt, krijgen we de run-time exception java.lang.VerifyError. Deze activiteit wordt uitgevoerd door de component ByteCodeVerifier. Als deze activiteit is voltooid, is het klasse-bestand klaar voor compilatie.
- Voorbereiding: JVM wijst geheugen toe voor klassevariabelen en initialiseert het geheugen op standaardwaarden.
- Resolutie: Het is het proces van het vervangen van symbolische verwijzingen van het type door directe verwijzingen. Dit wordt gedaan door in het methodegebied te zoeken naar de entiteit waarnaar wordt verwezen.
Initialisatie: In deze fase worden alle statische variabelen toegewezen met hun waarden die zijn gedefinieerd in de code en het statische blok (indien aanwezig). Dit wordt uitgevoerd van boven naar beneden in een klasse en van ouder naar kind in de klasse-hiërarchie.
In het algemeen zijn er drie class loaders :
- Bootstrap class loader: Elke JVM implementatie moet een bootstrap class loader hebben, die in staat is om vertrouwde klassen te laden. Deze laadt core java API klassen die aanwezig zijn in de “JAVA_HOME/jre/lib” directory. Dit pad is in de volksmond bekend als het bootstrap pad. Het is geïmplementeerd in native talen als C, C++.
- Extension class loader: Het is een kind van de bootstrap class loader. Het laadt de klassen die aanwezig zijn in de extensies mappen “JAVA_HOME/jre/lib/ext” (Extensie pad) of een andere map gespecificeerd door de java.ext.dirs systeem eigenschap. Deze wordt in java geïmplementeerd door de klasse sun.misc.Launcher$ExtClassLoader.
- Systeem-/toepassingsklassenlader: Dit is een kind van de class loader van de extensie. Het is verantwoordelijk voor het laden van klassen van het classpath van de toepassing. Het gebruikt intern een omgevingsvariabele die is toegewezen aan java.class.path. Het wordt ook in Java geïmplementeerd door de klasse sun.misc.Launcher$AppClassLoader.
public
class
Test {
public
static
void
main(String args)
{
System.out.println(String.
class
.getClassLoader());
System.out.println(Test.
class
.getClassLoader());
}
}
nulljdk.internal.loader.ClassLoaders$AppClassLoader@8bcc55f
Note: JVM volgt het Delegatie-Hiërarchie principe om klassen te laden. De systeemklasse lader delegeert het laadverzoek naar de uitbreidingsklasse lader en de uitbreidingsklasse lader delegeert het verzoek naar de bootstrap klasse lader. Als een klasse wordt gevonden in het bootstrap pad, wordt de klasse geladen anders gaat het verzoek opnieuw naar de extension class loader en dan naar de system class loader. Als de systeem-klassenlader er niet in slaagt de klasse te laden, krijgen we de run-time exception java.lang.ClassNotFoundException.
JVM-geheugen
- Methodegebied: In het methodegebied wordt alle informatie op klassenniveau opgeslagen, zoals de naam van de klasse, de naam van de directe bovenliggende klasse, informatie over methoden en variabelen, enzovoort, inclusief statische variabelen. Er is slechts een methode gebied per JVM, en het is een gedeelde bron.
- Heap gebied: Informatie van alle objecten wordt opgeslagen in de heap area. Er is ook één Heap Area per JVM. Het is ook een gedeelde bron.
- Stack area: Voor elke thread creëert JVM één run-time stack die hier wordt opgeslagen. Elk blok van deze stack wordt activeringsrecord/stack frame genoemd, waarin methodes worden opgeslagen. Alle lokale variabelen van die methode worden opgeslagen in hun corresponderende frame. Nadat een thread is beëindigd, wordt zijn runtime stack vernietigd door JVM. Het is geen gedeelde bron.
- PC-registers: Slaan het adres op van de huidige uitvoeringsinstructie van een thread. Vanzelfsprekend heeft elke thread afzonderlijke PC-registers.
- Native method stacks: Voor elke thread wordt een aparte native stack aangemaakt. Hierin wordt native methode-informatie opgeslagen.
Execution Engine
Execution engine voert de “.class” (bytecode) uit. Het leest de byte-code regel voor regel, gebruikt gegevens en informatie die in verschillende geheugengebieden aanwezig zijn en voert instructies uit. Hij kan in drie delen worden onderverdeeld:
- Interpreter: Het interpreteert de bytecode regel voor regel en voert dan uit. Het nadeel hiervan is dat wanneer een methode meerdere malen wordt aangeroepen, elke keer interpretatie nodig is.
- Just-In-Time Compiler(JIT) : Deze wordt gebruikt om de efficiëntie van een interpreter te vergroten. Het compileert de gehele bytecode en verandert deze in native code, zodat wanneer de interpreter herhaalde methode-aanroepen ziet, JIT directe native code voor dat deel levert, zodat herinterpretatie niet nodig is, waardoor de efficiëntie wordt verbeterd.
- Garbage Collector: Het vernietigt objecten waarnaar niet wordt verwezen. Voor meer informatie over Garbage Collector, zie Garbage Collector.
Java Native Interface (JNI) :
Het is een interface die interageert met de Native Method Libraries en biedt de native libraries (C, C++) die nodig zijn voor de uitvoering. Het stelt JVM in staat om C/C++ bibliotheken aan te roepen en om te worden aangeroepen door C/C++ bibliotheken die specifiek kunnen zijn voor hardware.
Native Method Libraries :
Het is een verzameling van de Native Libraries (C, C++) die nodig zijn voor de Execution Engine.
Dit artikel is geschreven door Gaurav Miglani. Als je GeeksforGeeks leuk vindt en een bijdrage wilt leveren, kun je ook een artikel schrijven via contribute.geeksforgeeks.org of mail je artikel naar [email protected]. Zie je artikel verschijnen op de GeeksforGeeks hoofdpagina en help andere Geeks.
Gelieve commentaar te schrijven als je iets onjuist vindt, of als je meer informatie wilt delen over het onderwerp dat hierboven is besproken.