Java Virtual Machine
description
Transcript of Java Virtual Machine
Java Virtual Machine
Specyfikacja - najważniejsze zagadnienia
XI.2003
Mirosław Szymański
Wydział Matematyki, Informatyki i Mechaniki Uniwersytetu Warszawskiego
2
Spis treści
• Wstęp
• Struktura JVM
• Instrukcje wirtualnej maszyny
• Pliki class
• Ładowanie, łączenie, inicjalizacja
• Wątki i blokady
• Kompilacja dla wirtualnej maszyny
• Literatura
Wstęp
4
Bytecode
• Zagadka: co robi poniższy program
Method void main(java.lang.String[])
0 getstatic #2
3 ldc #3
5 invokevirtual #4
8 return
5
Wstęp – historia Javy
• Cel powstania (początek prac – 1991)
– tworzenie oprogramowania dla urządzeń pracujących w sieci
• Wymagania / konsekwencje
– wspomaganie wielu architektur
– bezpieczeństwo
– krótki kod
• Pierwsza przeglądarka: HotJava (1994)
6
Wirtualna Maszyna Javy
• Wirtualny komputer posiadający:
– pamięć
– zestaw instrukcji (assembler ~ bytecode)
– wewnętrzne typy danych
• Specyfikacja definiuje tylko to co niezbędne
– format plików class
– instrukcje
Struktura JVM
8
Typy danych
9
Typy podstawowe (primitive)
• numeryczne– całkowite (integral)
• byte (8-bit), short (16-bit), int (32-bit), long (64-bit)• char (16-bit)
– zmienno-przecinkowe (floating-point)• float (32-bit), double (64-bit)
• boolean– true / false
• returnAddress– wskaźnik do instrukcji JVM
– używany przez jsr (jump subroutine), ret, jsr_w
– jedyny typ nie posiadający swojego odpowiednika w jęz. Java
10
Typy podstawowe (c.d.)
• byte, short, int, long – ze znakiem, dopełnienie do dwóch
• char – bez znaku, Unicode
• float, double – zgodne z IEEE 754
– +0.0, -0.0
– +∞, -∞
– +0.0 == -0.0 ale 1.0/0.0 = +∞ oraz 1.0/-0.0 = -∞
– NaN – Not a Number
• reprezentuje wynik błędnej operacji takiej jak dzielenie przez zero (?)
• w przeciwieństwie do wszystkich innych wartości jest nieuporządkowany
(wszystkie porównania dowolnej wartości z NaN dają false; NaN ≠ NaN)
• boolean – wyrażenia kompilowane są tak, aby używały typu int
– tablice typu boolean – dostęp przez baload oraz bastore
– w implementacji Sun’a boolean zajmuje 8 bitów
11
Typy referencyjne
• Wartościami są wskaźniki do obiektów
• Dzielimy na typy:
– klasowe (class types)
– tablicowe (array types)
– interfejsów (interface types)
• Specjalna wartość: null
– nie jest żadnego określonego typu (ale może być rzutowany na
dowolny typ)
– specyfikacja JVM nie określa żadnej konkretnej wartości kodującej
null
12
Obszary danych czasu wykonania
• Osobne dla każdego wątku– rejestr pc (program counter)
– stos JVM (JVM stack)• ramki
– stos metod typu native
• Współdzielone przez wątki– obszar metod (method area)
• constant pool
– sterta (heap)
13
Rejestr pc (program counter)
• wskaźnik (indeks) do bieżącej instrukcji
• każdy wątek posiada własny rejestr pc
• dla metod native wartość jest niezdefiniowana
14
Stos JVM
• każdy wątek posiada prywatny stos
• tworzony w tym samym czasie, co wątek
• analogiczny do stosu z języka C• zmienne, częściowe wyniki, wywoływanie metod i powroty
• pamięć obszaru nie musi być ciągła
• rozmiar stały lub zmieniany dynamicznie• Sun: pamięć nieciągła, powiększany ale nie zmniejszany,
maksymalny rozmiar – parametr „-oss”; ograniczenie na zużycie pamięci, wykrywanie nieskończonych rekursji.
• sytuacje wyjątkowe:
– podczas wykonania: StackOverflowError
– podczas tworzenia wątku: OutOfMemorError
15
Stos metod typu native
• rozmiar stały lub zmieniany dynamicznie• Sun: rozmiar stały – parametr „-ss”, nie sprawdza przepełnienia
stosu
• sytuacje wyjątkowe
– StackOverflowError
– OutOfMemoryError
16
Sterta (heap)
• dzielona przez wszystkie wątki
• pamięć na instancje klas i tablic• tworzona podczas uruchamiania JVM
• zarządzany przez garbage collector *• obiekty nigdy nie są jawnie dealokowane
• pamięć obszaru nie musi być ciągła
• rozmiar stały lub zmieniany dynamicznie• Sun: rozmiar zmienny, powiększany dynamicznie ale nie
zmniejszany; rozmiar początkowy i max. – „-ms” i „-mx”
• sytuacje wyjątkowe:
– OutOfMemoryError
17
Obszar metod (method area)
• dzielony przez wszystkie wątki
• przechowuje: runtime constant pool, dane klas (metody, kod metod, …)
• logicznie część sterty, ale twórca VM może nie chcieć żeby obszar ten był zarządzany przez garbage collector
• pamięć obszaru nie musi być ciągła
• rozmiar stały lub zmieniany dynamicznie• Sun: obsługiwany przez GC, kontrola rozmiaru min, max i init.
• sytuacje wyjątkowe:
– OutOfMemoryError
18
Constant pool
• posiadany przez wszystkie klasy i interfejsy
• reprezentuje tablicę constant_pool z pliku class
• używany przy dynamicznym linkowaniu (dynamic linking)
• odpowiednik tablicy symboli w konwencjonalnych językach, jednak zawiera więcej danych
• alokowany z obszaru metod
• sytuacje wyjątkowe:
– StackOverflowError, OutOfMemoryError
19
Ramki
• tworzone w momencie wywołania metody
• alokowane ze stosu JVM
• każda ramka posiada
– tablice zmiennych lokalnych
– operand stack
– referencję do constant pool klasy metody
20
Ramki – tablica zmiennych lokalnych
• pojedyncza zmienna może być typu:
– boolean, byte, char, short, int,float, reference, returnAddress
• para zmiennych może przechowywać wartości typów:
– long, double
• wartości long, double nie muszą być wyrównywane do 64-bitów
• wykorzystywane do przekazywania parametrów do metod
– specjalne znaczenie pozycji nr 0
21
Ramki – operand stack
• służy do– przekazania parametrów dla instrukcji JVM
– zwracania wyników instrukcji JVM
– zwracania wyników przez metody
• np.:iadd
…, value1, value2 → …, result
• wartości na stosie muszą być odpowiednich typów (sprawdzane podczas weryfikacji plików class)
iadd
22
Ramki (c.d.)
• zakończenie wywołania metody:
– normalne
• nie wystąpił wyjątek
• zostaje zwrócona wartość do metody wywołującej (operand stack)
– nienormalne, niespodziewane (abrupt)
• wystąpił wyjątek nie obsługiwany przez tą metodę
• wynik nie zostaje zwrócony
23
Inne ustalenia
• reprezentacja obiektów
• arytmetyka zmienno-przecinkowa
• specjalnie nazwane metody inicjalizacyjne– nazwy wspomagane przez kompilator (nie są prawidłowymi
identyfikatorami)
– <init>• odpowiednik konstruktora
• instrukcja wywołująca: invokespecial
– <cinit>• metoda inicjalizująca klasę lub interfejs
• statyczna, bez argumentów
• wywoływana bezpośrednio przez JVM, nigdy przez instrukcję JVM
24
Wyjątki
• podniesienie wyjątku powoduje natychmiastową zmianę miejsca wykonania
• przerywane jest działanie kolejnych metod, do momentu znalezienia klauzuli catch. Jeśli nie ma odpowiedniego catch to wątek kończy działanie.
• jeśli są klauzule finally, to są one wykonywane
• klauzule catch oraz finally reprezentowane są przez exception handler
25
Wyjątki – exception handlers
• przechowywane są w tablicy (tablica zapisana jest w pliku class)
• pojedynczy exception handler (EH):
– określa zakres instrukcji dla których jest aktywny
– określa typ obsługiwanego wyjątku
– zawiera adres kodu obsługującego ten wyjątek
• kolejność EH w tablicy jest ważna
– tablica przeglądana jest liniowo
Instrukcje wirtualnej maszyny
27
Instrukcje
• kod instrukcji ma 1 bajt
• rożne instrukcje dla poszczególnych typów
– np.: iload ładuje na stos zmienną typu int, fload - typu float
• zestaw instrukcji nie jest ortogonalny
28
Instrukcje (c.d.)
• rodzaje instrukcji
– load oraz store iload, iload_<n>, fload, iconst_<n>, …
– arytmetyczne iadd, dsub, …
– konwersja typów i2l, i2f, i2d, l2f, l2d, f2d; i2b, i2c, i2s, …
– operacje na obiektach new, newarray, arraylength, instanceof, …
– operacje na stosie arg. pop, dup, swap, …
– instrukcje skoku ifeq, ifnull, tableswitch, goto, jsr, …
– metody invokevirtual, return, ireturn, …
– podnoszenie wyjątków athrow
– synchronizacja monitorenter, monitorexit
Pliki class
30
Pliki class
• Typy danych: u1, u2, u4
• Tablice
– tables – zawierają elementy zmiennych rozmiarów (tablica (?))
– arrays – zawierają elementy stałych rozmiarów (tabela (?))
• struktury opisane za pomocą struktur z języka C
31
Pliki class (c.d.)• Plik class składa się z jednej struktury ClassFile:
ClassFile { u4 magic; // identyfikuje pliki class (0xCAFEBABE) u2 minor_version; u2 major_version; u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]; u2 access_flags; // ACC_PUBLIC, ACC_FINAL, ACC_SUPER,
// ACC_INTERFACE, ACC_ABSTRACT u2 this_class; // indeks do tablicy constant_pool u2 super_class; u2 interfaces_count; // liczba implementowanych interfejsów u2 interfaces[interfaces_count]; u2 fields_count; field_info fields[fields_count]; u2 methods_count; method_info methods[methods_count]; // reprezentuje wszystkie zadeklarowane metody
// (nie zawiera metod odziedziczonych) u2 attributes_count; attribute_info attributes[attributes_count];//SourceFile, Deprecated
//InnerClasses(?)}
32
Pliki class (c.d.)
• Deskryptory pól
FieldDescriptor → FieldType
ComponentType → FieldType
FieldType → BaseType | ObjectType | ArrayType
BaseType → B | C | D | F | I | J | S | Z
ObjectType → L<classname>;
ArrayType → [ComponentType
B – byte; C – char; D – double; F – float; I – int; J – long; S – short; Z – boolean
np.: double tablica[][][] → [[[D
33
Pliki class (c.d.)
• Deskryptory metod
MethodDescriptor → (ParameterDescriptor*) ReturnDescriptor
ParameterDescriptor → FieldType
ReturnDescriptor → FieldType | V
V – void
np.:
Object myMethod(int i, double d, Thread t)
(IDLjava/lang/Thread;)Ljava/lang/Object;
34
Pliki class (c.d.)
• Tablica constant_pool zawiera pola typu:– CONSTANT_Class
– CONSTANT_Fieldref
– CONSTANT_Methodref
– CONSTANT_InterfaceMethodref
– CONSTANT_String
– CONSTANT_Integer
– CONSTANT_Float
– CONSTANT_Long
– CONSTANT_Double
– CONSTANT_NameAndType
– CONSTANT_Utf8
35
Pliki class (c.d.)
• Pola (fields)
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_cout;
attribute_info attributes[attributes_count];
}
access_flags:
ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC,
ACC_FINAL, ACC_VOLATILE, ACC_TRANSIENT
attributes[]:
m.in.: ConstantValue, Deprecated
36
Pliki class (c.d.)
• Metody
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_cout;
attribute_info attributes[attributes_count];
}
access_flags:
ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC,
ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT,ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT,
ACC_STRICTACC_STRICT
attributes[]:
m.in.: Code, Exceptions, SyntheticCode, Exceptions, Synthetic, Deprecated
37
Pliki class (c.d.)
• Atrybut Code
Code_attribute { u2 attribute_name_index; u4 attribute_length; u2 max_stack; u2 max_locals; u4 code_length; u1 code[code_length]; u2 exception_table_length; { u2 start_pc; u2 end_pc; u2 handler_pc; u2 catch_type; } exception_table[exception_table_length]; u2 attributes_count; attribute_info attributes[attributes_count]; }
38
Ograniczenia na kod JVM
• Statyczne, m.in.:
– tablica z kodem musi być niepusta
– jedyne dozwolone instrukcje, to te wymienione w specyfikacji
– każda instrukcja ze skokiem musi wskazywać na kod instrukcji
wewnątrz danej metody
– instrukcja anewarray może być używana do tworzenia tablic o
maksymalnym wymiarze 255
– …
39
Ograniczenia na kod JVM (c.d.)
• Strukturalne, m.in.:
– każda instrukcja może być wykonana tylko z odpowiednią liczbą
argumentów i z odpowiednimi typami tych argumentów
– jeśli instrukcja może być wykonana w skutek różnych ścieżek
wykonania, to stos argumentów (operand stack) musi mieć tą samą
głębokość niezależnie od ścieżki
– każda instrukcja return musi odpowiadać typowi zwracanemu przez
daną metodę
– …
40
Weryfikacja plików class
• JVM nie może zakładać poprawności plików class
• Co jest sprawdzane:– 0 ≤ rozmiar stosu ≤ max_rozmiar
– wszystkie zmienne lokalne są używane prawidłowo
– argumenty instrukcji są odpowiednich typów
– klasy final nie posiadają podklas
– każda klasa (oprócz Object) posiada bezpośrednią nadklasę
– …
41
Ładowanie, łączenie, inicjalizacja
42
Ładowanie, łączenie, inicjalizacja
• Ładowanie (loading)
– proces wyszukiwania binarnej reprezentacji klasy lub interfejsu i utworzenie klasy/interfejsu
– klasy nie będące tablicami ładowane są przez class loader’a
– programista może zdefiniować własny class loader
• Łączenie
– weryfikacja
– „umiejscowienie” danej klasy/interfejsu w aktualnym stanie Wirtualnej Maszyny
43
Wątki i blokady (locks)
44
Wątki i blokady (locks)
• Niskopoziomowe mechanizmy korzystania przez wątki z pamięci dzielonej
• Pamięć:
– pamięć główna współdzielona przez wątki
– pamięć robocza wątku
• Pamięć główna zawiera kopie główne zmiennych
• Pamięć robocza zawiera kopie robocze zmiennych
• Pamięć główna: jeden obiekt – jedna blokada
• Akcje wykonywane przez pamięć główną:
– read, write, lock, unlock
• Akcje wykonywane wątek:
– use, assign, load, store, lock, unlock
• Powyższe akcje są atomowe.
45
Wątki i blokady (locks)
• read: (pamięć gł.) kopia główna → pamięć robocza
• load: (wątek) pamięć robocza → kopia robocza
• use: (wątek) kopia robocza → thread’s execution
engine
• assign: (wątek) thread’s e.e. → kopia robocza
• store: (wątek) kopia robocza → pamięć główna
• write: (pamięć gł.) pamięć główna → kopia główna
• lock: (wątek, operacja ściśle zsynchronizowana z pamięcią główną)
• unlock: (wątek, operacja ściśle zsynchronizowana z pamięcią główną)
46
Kompilacja
47
Operand stack i zmienne lokalne
iload_0 // push the int in local variable 0
iload_1 // push the int in local variable 1
iadd // pop two ints, add them, push result
istore_2 // pop int, store into local variable 2
48
Stałe, zmienne lokalne, instrukcje skoku
void spin() {
int i;
for (i = 0; i < 100; i++) {
;// Loop body is empty
}
}
Method void spin()
0 iconst_0 // Push int constant 0
1 istore_1 // Store into local variable 1 (i=0)
2 goto 8 // First time through don't increment
Loop body
5 iinc 1 1 // Increment local variable 1 by 1 (i++)
8 iload_1 // Push local variable 1 (i)
9 bipush 100 // Push int constant 100
11 if_icmplt 5 // Compare and loop if less than (i < 100)
14 return // Return void when done
49
Operacje arytmetyczne, parametry metod
int align2grain(int i, int grain) {
return ((i + grain-1) & ~(grain-1)));
}
Method int align2grain(int,int)
0 iload_1 // Push i
1 iload_2 // Push grain
2 iadd
3 iconst_1
4 isub
5 iload_2 // Push grain
6 iconst_1
7 isub
8 iconst_m18 iconst_m1
9 ixor9 ixor // (~x == -1^x)// (~x == -1^x)
10 iand
11 ireturn
50
Wywoływanie metod
int addTwo(int i, int j) {
return i + j;
}
int add12and13() {
return addTwo(12,13);
}
Method int add12and13()
0 aload_0 // Push local variable 0 (this)
1 bipush 12 // Push int constant 12
3 bipush 13 // Push int constant 13
5 invokevirtual #4 // Method Example.addtwo(II)I
8 ireturn // Return int on top of operand stack; it is
// the int result of addTwo()
51
Obiekty
Object create() { return new Object();}
Method java.lang.Object create() 0 new #1 // Class java.lang.Object 3 dup 4 invokespecial #4 // Method java.lang.Object.<init>()V 7 areturn
52
Obiekty (c.d.)
void setIt(int value) { i = value;}
int getIt() { return i;}
Method void setIt(int) 0 aload_0 1 iload_1 2 putfield #4 // Field Example.i I 5 return
Method int getIt() 0 aload_0 1 getfield #4 // Field Example.i I 4 ireturn
53
Try-catch
void catchOne() { try { tryItOut(); } catch (TestExc e) { handleExc(e); }}
Method void catchOne() 0 aload_0 // Beginning of try block 1 invokevirtual #6 // Method Example.tryItOut()V 4 return // End of try block; normal return 5 astore_1 // Store thrown value in local variable
1 6 aload_0 // Push this 7 aload_1 // Push thrown value 8 invokevirtual #5 // Invoke handler method:
// Example.handleExc(LTestExc;)V 11 return // Return after handling TestExc
Exception table: From To Target Type 0 4 5 Class TestExc
54
Try-catch-catch
void catchTwo() {
try {
tryItOut();
} catch (TestExc1 e) {
handleExc(e);
} catch (TestExc2 e) {
handleExc(e);
}
}
Method void catchTwo()
0 aload_0
1 invokevirtual #5
4 return
5 astore_1
6 aload_0
7 aload_1
8 invokevirtual #7
11 return
12 astore_1
13 aload_0
14 aload_1
15 invokevirtual #7
18 return
Exception table:
From To Target Type
0 4 5 Class TestExc1
0 4 12 Class TestExc2
55
Zagnieżdżony try-catch
void nestedCatch() {
try {
try {
tryItOut();
} catch (TestExc1 e) {
handleExc1(e);
}
} catch (TestExc2 e) {
handleExc2(e);
}
}
Method void nestedCatch()
0 aload_0
1 invokevirtual #8
4 return
5 astore_1
6 aload_0
7 aload_1
8 invokevirtual #7
11 return
12 astore_1
13 aload_0
14 aload_1
15 invokevirtual #6
18 return
Exception table:
From To Target Type
0 4 5 Class TestExc1
0 12 12 Class TestExc2
56
Try-finally
void tryFinally() {
try {
tryItOut();
} finally {
wrapItUp();
}
}
Method void tryFinally()
0 aload_0
1 invokevirtual #6
4 jsr 14 // Call finally block
7 return // End of try block
8 astore_1
9 jsr 14
12 aload_1 // Push thrown value…
13 athrow // …and rethrow the value to the invoker
14 astore_2 // Beginning of finally block
15 aload_0 // Push this
16 invokevirtual #5 // Method Example.wrapItUp()V
19 ret 2 // Return from finally block
Exception table:
From To Target Type
0 4 8 any
57
Try-catch-finallyvoid tryCatchFinally() {
try {
tryItOut();
} catch (TestExc e) {
handleExc(e);
} finally {
wrapItUp();
}
}
Method void tryCatchFinally() 0 aload_0 1 invokevirtual #4 4 goto 16 // Jump to finally block 7 astore_3 8 aload_0 9 aload_3 10 invokevirtual #6 13 goto 16 // Huh??? 16 jsr 26 19 return 20 astore_1 // Beginning of handler for exceptions
// other than TestExc, or exceptions // thrown while handling TestExc 21 jsr 26 // Call finally block 24 aload_1 // Push thrown value… 25 athrow // …and rethrow the value to the invoker 26 astore_2 27 aload_0 28 invokevirtual #5 31 ret 2
Exception table: From To Target Type 0 4 7 Class TestExc 0 16 20 any
58
Synchronizacja
• Metody typu synchronized
– nie zawierają instrukcji monitorenter / monitorexit
– rozpoznawane są przez JVM w momencie wykonywania
(flaga ACC_SYNCHRONIZED)
– przed wywołaniem metody JVM sam zajmuje monitor,
po poprawnym zakończeniu metody monitor jest zwalniany przez JVM
– jeśli w metodzie wystąpi nieobsługiwany wyjątek to monitor jest
automatycznie zwalniany przed przekazaniem wyjątku dalej
59
Synchronizacja (c.d.)
void onlyMe(Foo f) {
synchronized(f) {
doSomething();
}
}
Method void onlyMe(Foo)
0 aload_1 // Push f
1 astore_2 // Store it in local variable 2
2 aload_2 // Push local variable 2 (f)
3 monitorenter // Enter the monitor associated with f
4 aload_0 // Holding the monitor, pass this and...
5 invokevirtual #5 // ...call Example.doSomething()V
8 aload_2 // Push local variable 2 (f)
9 monitorexit // Exit the monitor associated with f
10 return // Return normally
11 aload_2 // In case of any throw, end up here
12 monitorexit // Be sure to exit monitor...
13 athrow // ...then rethrow the value to the invoker
Exception table:
From To Target Type
4 8 11 any
• blok synchronized– do synchronizacji służą instrukcje monitorenter / monitorexit
60
Hello world (zagadka c.d.)
class myClass{
public static void main(String args[]) {
System.out.println("Hello world!");
}
}
• javap –c myClass
Method myClass()
0 aload_0
1 invokespecial #1 <Method java.lang.Object()>
4 return
Method void main(java.lang.String[])
0 getstatic #2 <Field java.io.PrintStream out>
3 ldc #3 <String "Hello world!">
5 invokevirtual #4 <Method void println(java.lang.String)>
8 return
61
Literatura
• „Java Virtual Machine Specification, 2nd edition”Tim Lindholm, Frank Yellinhttp://java.sun.com/docs/books/vmspec/
• „Java Unleashed”praca zbiorowa, Sams.net Publishing
• „Inside the Java Virtual Machine”Bill Venners, Computing McGraw-Hillhttp://www.artima.com/insidejvm/blurb.html
Rysunki pochodzą z książki „Inside the Java Virtual Machine”.
Aktualna wersja prezentacji znajduje się na http://www.mirqos.prv.pl/mystuff.php
Dziękuję