JVM (Java Virtual Machine) fungiert als Laufzeit-Engine zur Ausführung von Java-Anwendungen. JVM ist diejenige, die die Hauptmethode in einem Java-Code aufruft. JVM ist ein Teil von JRE (Java Runtime Environment).
Java-Anwendungen werden WORA (Write Once Run Anywhere) genannt. Das bedeutet, dass ein Programmierer Java-Code auf einem System entwickeln kann und erwarten kann, dass er auf jedem anderen Java-fähigen System ohne jegliche Anpassung läuft. Dies alles ist dank der JVM möglich.
Wenn wir eine .java-Datei kompilieren, werden vom Java-Compiler .class-Dateien (enthält Byte-Code) mit denselben Klassennamen, die in der .java-Datei vorhanden sind, erzeugt. Diese .class-Datei durchläuft verschiedene Schritte, wenn wir sie ausführen. Diese Schritte zusammen beschreiben die gesamte JVM.
Class Loader Subsystem
Es ist hauptsächlich für drei Aktivitäten zuständig.
- Laden
- Verknüpfen
- Initialisierung
Laden: Der Class-Loader liest die „.class“-Datei, erzeugt die entsprechenden Binärdaten und speichert sie im Methodenbereich. Für jede „.class“-Datei speichert die JVM die folgenden Informationen im Methodenbereich.
- Der voll qualifizierte Name der geladenen Klasse und ihre unmittelbare Elternklasse.
- Ob die „.class“-Datei zu einer Klasse, einem Interface oder einem Enum gehört.
- Modifier-, Variablen- und Methodeninformationen usw.
Nach dem Laden der „.class“-Datei erzeugt die JVM ein Objekt vom Typ Class, um diese Datei im Heap-Speicher zu repräsentieren. Bitte beachten Sie, dass dieses Objekt vom Typ Class ist, der im Paket java.lang vordefiniert ist. Dieses Class-Objekt kann vom Programmierer verwendet werden, um Informationen auf Klassenebene zu erhalten, wie z. B. den Namen der Klasse, den Namen des Elternteils, Methoden und Variableninformationen usw. Um diese Objektreferenz zu erhalten, können wir die Methode getClass() der Klasse Object verwenden.
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;
}
}
StudentgetNamesetNamegetRoll_nosetRoll_nonameroll_No
Hinweis: Für jede geladene „.class“-Datei wird nur ein Objekt der Klasse erzeugt.
Student s2 = new Student();// c2 will point to same object where // c1 is pointingClass c2 = s2.getClass();System.out.println(c1==c2); // true
Verknüpfen: Führt die Überprüfung, Vorbereitung und (optional) die Auflösung durch.
- Verifizierung: Sie stellt die Korrektheit der .class-Datei sicher, d. h. sie prüft, ob diese Datei richtig formatiert und von einem gültigen Compiler erzeugt wurde oder nicht. Wenn die Verifizierung fehlschlägt, erhalten wir die Laufzeit-Exception java.lang.VerifyError. Diese Aktivität wird von der Komponente ByteCodeVerifier ausgeführt. Sobald diese Aktivität abgeschlossen ist, ist die Klassendatei bereit für die Kompilierung.
- Vorbereitung: Die JVM weist Speicher für Klassenvariablen zu und initialisiert den Speicher auf Standardwerte.
- Auflösen: Es ist der Prozess des Ersetzens symbolischer Referenzen vom Typ durch direkte Referenzen. Dies geschieht durch die Suche im Methodenbereich, um die referenzierte Entität zu finden.
Initialisierung: In dieser Phase werden alle statischen Variablen mit ihren im Code und statischen Block (falls vorhanden) definierten Werten zugewiesen. Dies wird in einer Klasse von oben nach unten und in der Klassenhierarchie vom Elternteil zum Kind ausgeführt.
In der Regel gibt es drei Klassenlader :
- Bootstrap-Klassenlader: Jede JVM-Implementierung muss einen Bootstrap-Klassenlader haben, der in der Lage ist, vertrauenswürdige Klassen zu laden. Er lädt Kern-Java-API-Klassen, die im Verzeichnis „JAVA_HOME/jre/lib“ vorhanden sind. Dieser Pfad ist im Volksmund als Bootstrap-Pfad bekannt. Er ist in nativen Sprachen wie C, C++ implementiert.
- Extension class loader: Er ist ein Kind des Bootstrap-Klassenladers. Er lädt die Klassen, die in den Erweiterungsverzeichnissen „JAVA_HOME/jre/lib/ext“ (Erweiterungspfad) oder in einem anderen Verzeichnis, das durch die Systemeigenschaft java.ext.dirs angegeben wird, vorhanden sind. Er wird in Java von der Klasse sun.misc.Launcher$ExtClassLoader implementiert.
- System-/Anwendungsklassenlader: Er ist ein Kind des Erweiterungsklassenladers. Er ist dafür verantwortlich, Klassen aus dem Applikationsklassenpfad zu laden. Er verwendet intern eine Umgebungsvariable, die auf java.class.path abgebildet wird. Er ist auch in Java durch die Klasse sun.misc.Launcher$AppClassLoader implementiert.
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
Hinweis: Die JVM folgt beim Laden von Klassen dem Prinzip der Delegationshierarchie. Der Systemklassenlader delegiert die Ladeanforderung an den Erweiterungsklassenlader und der Erweiterungsklassenlader delegiert die Anforderung an den Bootstrap-Klassenlader. Wenn eine Klasse im Bootstrap-Pfad gefunden wird, wird die Klasse geladen, andernfalls wird die Anforderung erneut an den Extension Class Loader und dann an den System Class Loader weitergeleitet. Wenn der System-Klassenlader die Klasse nicht laden kann, erhalten wir die Laufzeit-Exception java.lang.ClassNotFoundException.
JVM Speicher
- Methodenbereich: Im Methodenbereich werden alle Informationen auf Klassenebene wie Klassenname, unmittelbarer Name der Elternklasse, Methoden- und Variableninformationen usw. gespeichert, einschließlich statischer Variablen. Es gibt nur einen Methodenbereich pro JVM, und es ist eine gemeinsam genutzte Ressource.
- Heap-Bereich: Im Heap-Bereich werden Informationen zu allen Objekten gespeichert. Es gibt ebenfalls nur einen Heap-Bereich pro JVM. Er ist ebenfalls eine gemeinsam genutzte Ressource.
- Stack-Bereich: Für jeden Thread legt die JVM einen Laufzeit-Stack an, der hier gespeichert wird. Jeder Block dieses Stacks wird als Aktivierungssatz/Stackframe bezeichnet, der Methodenaufrufe speichert. Alle lokalen Variablen dieser Methode werden in ihrem entsprechenden Frame gespeichert. Nachdem ein Thread beendet ist, wird sein Laufzeitstack von der JVM zerstört. Es handelt sich nicht um eine gemeinsam genutzte Ressource.
- PC-Register: Speichern die Adresse der aktuellen Ausführungsanweisung eines Threads. Offensichtlich hat jeder Thread separate PC-Register.
- Native Methodenstapel: Für jeden Thread wird ein eigener nativer Stack angelegt. Er speichert native Methodeninformationen.
Die Ausführungsmaschine
Die Ausführungsmaschine führt die „.class“ (Bytecode) aus. Sie liest den Bytecode zeilenweise, verwendet Daten und Informationen, die in verschiedenen Speicherbereichen vorhanden sind, und führt Anweisungen aus. Sie kann in drei Teile unterteilt werden:
- Interpreter: Er interpretiert den Bytecode Zeile für Zeile und führt ihn dann aus. Der Nachteil hierbei ist, dass bei mehrfachem Aufruf einer Methode jedes Mal eine Interpretation erforderlich ist.
- Just-In-Time Compiler(JIT) : Er wird eingesetzt, um die Effizienz eines Interpreters zu erhöhen. Er kompiliert den gesamten Bytecode und wandelt ihn in nativen Code um, so dass JIT immer dann, wenn der Interpreter wiederholte Methodenaufrufe sieht, direkten nativen Code für diesen Teil bereitstellt, so dass keine Neuinterpretation erforderlich ist und somit die Effizienz verbessert wird.
- Garbage Collector: Er vernichtet nicht referenzierte Objekte. Weitere Informationen zum Garbage Collector finden Sie unter Garbage Collector.
Java Native Interface (JNI) :
Es ist eine Schnittstelle, die mit den Native Method Libraries interagiert und die für die Ausführung erforderlichen nativen Bibliotheken (C, C++) bereitstellt. Sie ermöglicht es der JVM, C/C++-Bibliotheken aufzurufen und von C/C++-Bibliotheken aufgerufen zu werden, die hardware-spezifisch sein können.
Native Methodenbibliotheken :
Es ist eine Sammlung der nativen Bibliotheken (C, C++), die von der Execution Engine benötigt werden.
Dieser Artikel wurde von Gaurav Miglani beigesteuert. Wenn Ihnen GeeksforGeeks gefällt und Sie einen Beitrag leisten möchten, können Sie auch einen Artikel über contribute.geeksforgeeks.org schreiben oder eine E-Mail an [email protected] senden. Sehen Sie, wie Ihr Artikel auf der GeeksforGeeks-Hauptseite erscheint, und helfen Sie anderen Geeks.
Bitte schreiben Sie Kommentare, wenn Sie etwas falsch finden oder weitere Informationen zu dem oben besprochenen Thema mitteilen möchten.