Wirtualna maszyna Java (JVM) to podstawowy komponent środowiska Java Runtime Environment (JRE), który umożliwia uruchamianie programów Java na dowolnej platformie bez modyfikacji. JVM działa jako interpreter pomiędzy kodem bajtowym Java a bazowym sprzętem, zapewniając słynną funkcję Java Write Once Run Anywhere (WORA).
ciąg Java do tablicy
- Źródło Java (.java) -> skompilowane przez javac -> kod bajtowy (.class)
- JVM ładuje kod bajtowy, sprawdza, czy go łączy, a następnie wykonuje
- Wykonanie może obejmować interpretację kodu bajtowego lub użycie kompilacji Just-In-Time (JIT) w celu konwersji gorącego kodu na natywny kod maszynowy w celu zwiększenia wydajności
- Wyrzucanie elementów bezużytecznych działa w tle, aby odzyskać pamięć z nieużywanych obiektów
Architektura JVM
Poniższy obraz przedstawia architekturę i kluczowe komponenty JVM.
Komponenty architektury JVM
Teraz omówimy szczegółowo każdy komponent JVM.
1. Podsystem modułu ładującego klasy
Odpowiada głównie za trzy działania.
1. Ładowanie
- Odczytuje pliki .class i przechowuje metadane klas w obszarze metod.
- Tworzy obiekt klasy na stercie reprezentujący załadowaną klasę.
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(); } }
Wyjście
Main method started. GFG class is loaded by the JVM! Class loaded successfully. Method of GFG class is executed.
Notatka: Za każdego załadowanego .klasa tylko plik jeden tworzony jest obiekt klasy.
2. Łączenie: Odpowiedzialny za przygotowanie załadowanej klasy do wykonania. Obejmuje trzy kroki:
Java zamień wszystko
- Weryfikacja: Zapewnia, że kod bajtowy jest zgodny z regułami JVM i jest bezpieczny do wykonania.
- Przygotowanie: Przydziela pamięć dla zmiennych statycznych i przypisuje wartości domyślne.
- Rezolucja: Konwertuje odniesienia symboliczne na bezpośrednie odniesienia w pamięci.
3. Inicjalizacja
- Przypisuje wartości rzeczywiste do zmiennych statycznych.
- Wykonuje bloki statyczne zdefiniowane w klasie.
Typy modułów ładujących klasy
- Moduł ładujący klasy Bootstrap: Ładuje podstawowe klasy Java (JAVA_HOME/lib).
- Moduł ładujący klas rozszerzeń: Ładuje klasy z katalogu rozszerzeń (JAVA_HOME/jre/lib/ext).
- Moduł ładujący klasy systemu/aplikacji: Ładuje klasy ze ścieżki klas aplikacji.
// 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()); } }
Wyjście
null jdk.internal.loader.ClassLoaders$AppClassLoader@8bcc55f
2. Obszary pamięci JVM
- Obszar metody: Przechowuje informacje na poziomie klasy, takie jak zmienne metod klasy nadrzędnej i dane statyczne. Udostępniane w JVM.
- Obszar sterty: Przechowuje wszystkie obiekty. Udostępniane w JVM.
- Powierzchnia stosu: Każdy wątek ma swój własny stos środowiska wykonawczego; przechowuje wywołania metod lokalnych w ramkach stosu. Zniszczony po zakończeniu wątku.
- Rejestry komputerów: Przechowuj adres aktualnie wykonywanej instrukcji dla każdego wątku.
- Stosy metod natywnych: Każdy wątek ma oddzielny stos do wykonywania metod natywnych.
3. Silnik wykonawczy
Silnik wykonawczy wykonuje .class (kod bajtowy). Odczytuje kod bajtowy linia po linii, wykorzystuje dane i informacje znajdujące się w różnych obszarach pamięci i wykonuje instrukcje. Można go podzielić na trzy części:
- Interpretator: Interpretuje kod bajtowy linia po linii, a następnie wykonuje. Wadą jest to, że gdy jedna metoda jest wywoływana wiele razy, za każdym razem wymagana jest interpretacja.
- Kompilator just-in-time (JIT): Służy do zwiększenia wydajności tłumacza. Kompiluje cały kod bajtowy i zmienia go na kod natywny, więc za każdym razem, gdy interpreter widzi powtarzające się wywołania metod, JIT zapewnia bezpośredni kod natywny dla tej części, więc ponowna interpretacja nie jest wymagana, co poprawia wydajność.
- Zbieracz śmieci: Niszczy obiekty, do których nie ma odniesienia. Więcej informacji na temat modułu zbierającego śmieci można znaleźć w artykule Zbieracz śmieci .
4. Natywny interfejs Java (JNI)
Jest to interfejs, który współdziała z bibliotekami metod natywnych i udostępnia biblioteki natywne (C C++) wymagane do wykonania. Umożliwia JVM wywoływanie bibliotek C/C++ i wywoływanie przez biblioteki C/C++, które mogą być specyficzne dla sprzętu.
5. Biblioteki metod natywnych
Są to zbiory bibliotek natywnych wymaganych do wykonywania metod natywnych. Obejmują one biblioteki napisane w językach takich jak C i C++.
typy referencyjne Java