Java Virtual Machine Programmiermethodik Eva Zangerle Universität Innsbruck Überblick Einführung Java – Ein erster Überblick Objektorientierung Vererbung und Polymorphismus Ausnahmebehandlung Pakete und Javadoc Spezielle Themen Generische Programmierung Java Collection-Framework Streams Unit-Tests Entwurfsmuster - Eine Einführung GUI-Programmierung JVM - Überblick Java Virtual Machine JVM - Struktur Ausblick Garbage Collection Programmiermethodik - Java Virtual Machine 2 JVM - Überblick Java allgemein • Architektur von Java Programmiersprache Format für .class-Dateien Java-API JVM (Java Virtual Machine) • Laufzeitumgebung Abstrakte Maschine Menge von Instruktionen Speicherverwaltung Dynamisches Laden von Klassen (class-loading) Unterstützt Reflection (3. Semester) Verwaltet Nebenläufigkeit (3. Semester) • Diese Vorlesung Basiert auf [Venners 2000] Programmiermethodik - Java Virtual Machine 4 Programmierumgebung Übersetzungsumgebung Laufzeitumgebung Source A.java B.java Eigene class-Dateien C.java Java Compiler A.class B.class A.class Lokal, über Netzwerk etc. C.class Eigene class-Dateien Programmiermethodik - Java Virtual Machine B.class C.class Java Virtual Machine Object.class String.class Java-API class-Dateien 5 Übersetzung – Interpretierung (Wiederholung) • Übersetzung (Kompilierung) Der Programmcode wird in einen Zielcode (z.B. Maschinencode) umgesetzt. Laufzeitumgebung führt diesen Code aus. Vorteile Nachteile Effizienz (sowohl Laufzeit als auch Speicher) Nicht portierbar (muss neu kompiliert werden) • Interpretierung Interpreter liest jede Instruktion. Verifiziert den Code. Gibt den korrekte Code an die Laufzeitumgebung weiter. Vorteile Nachteile Portierbarkeit Dynamisch, d.h. bei Änderungen muss die Applikation nicht neu gestartet werden. Effizienz (langsam) Programmiermethodik - Java Virtual Machine 6 Hybrider Ansatz (Java, C#, …) • Idee Aus dem Programmcode wird ein portabler Zwischencode erzeugt, der auf verschiedenen Plattformen interpretiert werden kann. MyProg.class MyProg.class MyProg.class MyProg.class Java-Plattform für Linux Java-Plattform für Windows Java-Plattform für TV Java-Plattform für Toaster Linux Rechner Windows Rechner TV Toaster Programmiermethodik - Java Virtual Machine 7 Bytecode • Zwischencode der von der JVM interpretiert wird. • Ein beliebiger (gültiger) Java-Compiler muss gültigen Bytecode erzeugen (.class-Dateien). • Inhalt Informationen über Referenzen auf andere Klassen Klassenhierarchien Methodensignaturen Code von Methoden etc. Referenzen werden beim Ladeprozess aufgelöst. • .class-Datei Binärdatei Immer big-endian (unabhängig von der darunterliegenden Architektur; most significant bit in niedrigster Adresse) Kompakt (z.B. für Netzwerkübertragung) Programmiermethodik - Java Virtual Machine 8 Struktur einer .class-Datei [Web 2012] Programmiermethodik - Java Virtual Machine 9 Virtuelle Maschine • Die virtuelle Maschine unterstützt Plattformunabhängigkeit Sicherheit Mobilität (im Netzwerk) • Die JVM ist eine abstrakte Maschine. Spezifikation gibt einige Teile vor (z.B. JVM muss Bytecode interpretieren können). Implementierung wird aber offen gelassen (z.B. unterschiedliche Ansätze den Bytecode zu interpretieren). • Hauptaufgaben Klassendateien laden Bytecode in diesen Klassendateien ausführen Programmiermethodik - Java Virtual Machine 10 Programmausführung • Einfachster Ansatz (in Software) Interpretierung des Bytecodes • Just-in-time Übersetzung (JIT) Bytecode wird in Maschinencode übersetzt (beim ersten Aufruf einer Methode). Erzeugter Code kommt in einen Cache, um später darauf zuzugreifen (benötigt mehr Speicher!). • Adaptive-Optimizer Interpretierung Oft benutzte Teile werden mit der Zeit (Monitoring) in Maschinencode übersetzt. • JVM in Hardware Programmiermethodik - Java Virtual Machine 11 JVM in Software (1) Java Virtual Machine Eigene Class-Dateien Java-API Class-Dateien Class loader Bytecode Execution engine Aufruf nativer Methoden Betriebssystem Programmiermethodik - Java Virtual Machine 12 JVM in Software (2) • Java-Programm interagiert mit dem Betriebssystem über native Methoden. • Java hat daher 2 Arten von Methoden Java-Methoden (z.B. im eigenen Java-Programm implementiert) Native Methoden (in C, C++, Assembler und entsprechend übersetzt) Beim Aufruf nativer Methoden lädt die JVM die entsprechenden dynamischen Bibliotheken (plattformabhängig). • Eigene native Methoden? JNI (Java Native Interface) Damit ist das entsprechende Programm nicht mehr plattformunabhängig! Programmiermethodik - Java Virtual Machine 13 JVM – Struktur (Ein kurzer Überblick) Virtuelle Maschine • Spezifikation beschreibt das Verhalten an Hand von Subsystemen Speicherbereichen Datentypen Instruktionen • Abstrakte Beschreibung Beschreibt das Verhalten der JVM. Beschreibt nicht die genaue innere Architektur! Implementierung hängt vom Entwickler der JVM ab. Programmiermethodik - Java Virtual Machine 15 Virtuelle Maschine (Architektur) Class-Dateien Method area Class loader subsystem Heap Java stacks PC registers Native method stacks Laufzeitdatenbereiche Execution engine Programmiermethodik - Java Virtual Machine Schnittstelle für native Methoden Bibliotheken für native Methoden 16 Virtuelle Maschine (Datenbereich) • Jede JVM hat genau einen Methodenbereich (method area) Bytecode Class-Daten Heap Objektspeicher (alle Objekte werden hier abgelegt) Klassen -daten Klassen -daten Klassen -daten Klassen -daten Objekt Objekt Klassen -daten Methodenbereich Programmiermethodik - Java Virtual Machine Objekt Objekt Objekt Heap 17 Virtuelle Maschine (Thread-spezifische Verwaltung) • Daten zur Laufzeit Thread 1 Thread 2 Thread 3 Thread 1 Stack frame Stack frame Stack frame Thread 2 Stack frame Stack frame Stack frame Stack frame Stack frame Thread 3 Stack frame PC-Register Programmiermethodik - Java Virtual Machine Java-Stacks Thread 3 Native Methoden Stacks 18 Datentypen der JVM float Numerische Typen Floating-Point Typen double byte Primitive Typen boolean Integrale Typen short int returnAddress long Klassentypen Referenztypen reference char Interface-Typen Array-Typen Programmiermethodik - Java Virtual Machine 19 Laden von Klassen (Class loading) in der JVM Loading • Lokalisierung der binären Repräsentation eines „Typs“ (Klasse, Interface) • Laden der Daten Linking • Parsen des „Typs“ und Aufnahme in die aktuelle Verwaltung der JVM • Verifikation des Codes • Vorbereitung • Auflösung (von symbolischen Referenzen) Initialization • Aufruf des Initialisierers Programmiermethodik - Java Virtual Machine 20 Wann wird eine Klasse geladen? • Nicht festgelegt Flexible JVM-Spezifikation Loading vor Linking Linking vor Initialization Initialization vor erster Verwendung („active use“) „Active use“ new-Anweisung, implizit bei String, Aufruf einer statischen Methode, Initialisierung einer Subklasse, Aufruf der main-Methode usw. • Normalerweise wird das Laden möglichst lange hinausgezögert! Ressourcen werden erst dann belegt, wenn sie wirklich benötigt werden. Ist aber keine Anforderung, d.h. Laden kann auch zu einem früheren Zeitpunkt erfolgen! Programmiermethodik - Java Virtual Machine 21 Klassenlader • Damit der Bytecode von der JVM verarbeitet werden kann, muss ein Klassenlader (class loader) die benötigte Klasse laden. • Alle Referenztypen (außer Arrays) werden entweder durch den Bootstrap-Klassenlader oder durch einen benutzerdefinierten Klassenlader geladen. • Bootstrap-Klassenlader ist Teil der JVM. Lädt alle Systemklassen • Benutzerdefinierte Lader („normale“ Java-Klassen) Werden von java.lang.ClassLoader abgeleitet. Können bestimmte Zusatzaufgaben übernehmen. Caching Prefetching spezielle Überprüfungen etc. Programmiermethodik - Java Virtual Machine 22 Method Area • Nachdem der Klassenlader eine Klasse geladen hat, gibt er Sie an die JVM weiter. • Die JVM extrahiert Informationen und speichert diese Informationen über den Typ in der so genannten Method Area. • Implementierung Hängt vom JVM Designer ab (Datenstruktur, Größe, Verwaltung …). • Für jeden Typ Basisinformationen wie Name (voll qualifiziert), Name der Superklasse, Unterscheidung ob Klasse oder Interface, Zugriffsmodifikatoren, Liste von Interfaces (voll qualifiziert) … Zusätzlich: Constant Pool, Attribut- und Methodeninformationen, alle statische Variablen (nicht Konstanten), Referenz auf den Klassenlader, Referenz auf Klasse Class Methodentabellen (für schnellen Zugriff) Programmiermethodik - Java Virtual Machine 23 Heap • Innerhalb einer JVM gibt es einen Heap. Alle Threads eines Programms teilen sich diesen. Jedes Programm läuft aber in einer eigenen JVM-Instanz! • Bei der Objekterzeugung (auch Array) wird Speicher vom Heap angefordert Die JVM hat eine Instruktion um Speicher anzufordern. Es existiert aber keine Instruktion für die Freigabe. Speicherfreigabe erfolgt durch den sogenannten Garbage-Collector. Programmiermethodik - Java Virtual Machine 24 Objektrepräsentation (1) • Objektrepräsentation ist nicht festgelegt. • Beispiel: Monolithische Repräsentation Ptr auf Klassendaten Objektreferenz Ptr auf Heap Instanzdaten Instanzdaten Instanzdaten Heap Klassen -daten Methodenbereich Programmiermethodik - Java Virtual Machine 25 Objektrepräsentation (2) • Geteilte Repräsentation Handle-Pool Objektreferenz Ptr auf Heap Ptr auf Objektpool Ptr auf Klassendaten Objektpool Instanzdaten Instanzdaten Heap Klassen -daten Methodenbereich Programmiermethodik - Java Virtual Machine 26 Spezielles Beispiel mit Arrays int [][] ar = new int [2][2]; Ptr auf Klassendaten length (=2) ar[0] (Arrayreferenz) ar[1] (Arrayreferenz) Ptr auf Klassendaten length (=2) ar[0][0] (int) ar[0][1] (int) ar (Arrayreferenz) Ptr auf Klassendaten length (=2) ar[1][0] (int) ar[1][1] (int) Heap Klassen daten für [[ ]] Klasse ndaten für [ ] Methodenbereich Programmiermethodik - Java Virtual Machine 27 Vererbung • Code für Methoden wird bei der Vererbung nicht dupliziert! Z.B. Klasse C1 und C2 teilen sich den Code von m1() C1 ~x : int +m1() C1 o1 = new C1(); C2 o2 = new C2(); o2.m1(); Code von C1 o2.x = 10; o2.y = 10; C2 C2 hat ein lokales x! Nicht gemeinsam! ~y : int +m2() Programmiermethodik - Java Virtual Machine 28 Vererbung (Implementierung) Referenz auf Superklasse Methodenbereich Instanzenraum x m2() m1() x y Speicher C1 C2 o1 Programmiermethodik - Java Virtual Machine o2 29 Dynamisches Binden (1) C1 ~x : int +m1() +is Null() : boolean C2 ~y : int +m2() +is Null() : boolean Programmiermethodik - Java Virtual Machine C1 c; C1 o1 = new C1(); C2 o2 = new C2(); boolean b; … if(…) c = o1; else Dynamisches Binden! c = o2; b = c.isNull(); 30 Dynamisches Binden (2) • Jede Klasse hat eine so genannte Dispatch-Tabelle. Ziel: Operation mit Methode verknüpfen. Tabelle hat eine Liste der Methoden, die in der Klasse implementiert werden und einen Pointer auf die Superklasse. Lookup zur Laufzeit – Performance!? Dispatch-Tabelle m1() isNull() c.isNull() m2() isNull() x x y Speicher C1 C2 o1 Programmiermethodik - Java Virtual Machine o2 31 Stack • Für jeden Thread wird ein eigener Stack verwaltet. Stack verwaltet so genannte Frames. • Die JVM führt nur 2 Operationen auf den Stack direkt aus. push und pop (von Frames) • Aktuelle Ausführung current current current current method (Methode die aktuell ausgeführt wird) frame class (Klasse, in der die Methode definiert ist) constant pool (Konstanten der aktuellen Klasse) • JVM verwaltet die Ausführung. • Wenn die JVM auf Operationen trifft, die auf Daten im aktuellen Frame operieren, dann führt sie diese im aktuellen Frame aus. • Tatsächliche Verwaltung des Stacks ist implementierungsabhängig! Programmiermethodik - Java Virtual Machine 32 Frame • Wird beim Aufruf einer Methode erzeugt. Wenn ein Thread eine Methode aufruft. • Die ausführende Methode speichert Parameter, lokale Variablen, Zwischenresultate und weitere Daten in diesem Frame. • Beendigung einer Methode Normal Durch Ausnahme • Bei Beendigung nimmt die JVM den Frame vom Stack und verwirft ihn. • Der Frame der vorhergehenden Methode (aufrufenden Methode) wird zum current frame. Programmiermethodik - Java Virtual Machine 33 Aufbau eines Frames • 3 Bereiche Lokale Variablen Operandenstack Frame-Daten Array Über Index Zugriff auf Variablen Array nach dem Stack-Prinzip verwaltet Arbeitsplatz für die JVM JVM hat daher eine Stack-basierte Architektur! Constant pool resolution Verwaltung von Ausnahmen • Größe Speicherplatzanforderung für lokale Variablen und Operandenstack wird zur Übersetzungszeit berechnet und für jede Methode in die class-Datei eingefügt (Größe der Frame-Daten implementierungsabhängig). Beim Aufruf einer Methode werden diese Daten verwendet. Programmiermethodik - Java Virtual Machine 34 JVM-Instruktionen (1) • JVM-Instruktion opcode (1 Byte) für die Instruktion die ausgeführt werden muss 0 oder mehrere Operanden (1 oder mehrere Bytes) für die Operation • Innere Schleife der JVM execution engine (ohne Ausnahmen) do { fetch an opcode; if (operands) fetch operands; execute the action for the opcode; } while (there is more to do); Programmiermethodik - Java Virtual Machine 35 JVM-Instruktionen (2) • Die meisten Operationen nehmen Operanden vom Stack und geben das Resultat auf den Stack. • Viele Instruktionen haben mehrere Versionen. Abhängig von den Typen der Operanden Unterscheidung durch Präfix i,l,f,d,b,s,c,a Beispiele iload – Integer laden dload – Double laden …. Programmiermethodik - Java Virtual Machine 36 JVM-Instruktionen (3) • Unterschiedliche Typen Laden/Speichern (z.B. load, store, push, lcd, wide …..) Arithmetik/Logische Operationen (z.B. add, sub, mul, shl, shr, or, xor ….. Typkonvertierung (z.B. i2l, i2f, i2b, …) Objekterzeugung/-manipulation (z.B. new, newarray, aload, astore, …) Operandenstack-Management (z.B. pop, pop2, swap ….) Kontrollfluss (z.B. ifeq, iflt, ifle, ifne, tableswitch, lookupswitch, ..) Methodenaufruf (z.B. invokevirtual, invokeinterface, invokestatic, invokespecial ….) Ausnahmen/finally Programmiermethodik - Java Virtual Machine 37 Parameter (Beispiel) public class Example { public static int runClassMethod(int i, long l, float f, double d, Object o, byte b) { return 0; } public int runInstanceMethod(char c, double d, short s, boolean b) { return 0; } } runClassMethod() runInstanceMethod() index type parameter 0 int int i 1 long long l 3 float float f 4 double double d 6 7 reference int Object o byte b Programmiermethodik - Java Virtual Machine index type parameter 0 1 reference int hidden this char c 2 double double d 4 5 int int short s boolean b 38 Operandenstack (Beispiel) iload_0 iload_1 iadd istore_2 Vor der Ausführung lokale Variablen 0 1 2 100 98 OperandenStack Programmiermethodik - Java Virtual Machine Nach iload_0 0 1 2 100 98 100 Nach iload_1 0 1 2 100 98 100 98 Nach iadd 0 1 2 100 98 Nach istore_2 0 1 2 100 98 198 198 39 Bytecode anzeigen – javap • javap ist ein Disassembler Defaultmäßig gibt er nur die öffentliche Schnittstelle aus. -c gibt den Code für alle Methoden aus. -l gibt den Code für alle Variablen aus. -private zeigt alle Variablen und Klassen. -s für interne Typsignaturen. • Weitere Informationen: http://download.oracle.com/javase/1,5.0/docs/tooldocs/windows/javap.html Programmiermethodik - Java Virtual Machine 40 Beispiel (1) public class FactorialTest { public static int factorial(int n) { return (n == 0) ? 1 : n * factorial(n - 1); } } public static void main(String[] args) { for (int i = 1; i < 10; i++) { System.out.println(factorial(i)); } } javap –c FactorialTest: Compiled from "FactorialTest.java" public class FactorialTest { public FactorialTest(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return Programmiermethodik - Java Virtual Machine 41 Beispiel (2) } public static int factorial(int); Code: 0: iload_0 1: ifne 8 4: iconst_1 5: goto 16 8: iload_0 9: iload_0 10: iconst_1 11: isub 12: invokestatic #2 // Method factorial:(I)I 15: imul 16: ireturn public static void main(java.lang.String[]); Code: 0: iconst_1 1: istore_1 2: iload_1 3: bipush 10 5: if_icmpge 24 8: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream; 11: iload_1 12: invokestatic #2 // Method factorial:(I)I 15: invokevirtual #4 // Method java/io/PrintStream.println:(I)V 18: iinc 1, 1 21: goto 2 24: return Programmiermethodik - Java Virtual Machine 42 Java 7 • Bytecode für die JVM kann im Prinzip von beliebigen Programmiersprachen kommen (sofern ein Compiler existiert, der gültigen Bytecode erzeugt). Es existieren zum Beispiel Bytecode-Compiler für Python oder Ruby. Problem: Diese Sprachen sind dynamisch typisierte Sprachen! Java und die JVM sind aber auf statische Typspezifizierung zur Übersetzungszeit ausgelegt. Nur mit Tricks (und Performance-Verlust) können dynamisch typisierte Sprachen in Bytecode übersetzt werden. • Daher wurde eine neue Bytecode-Instruktion (invokedynamic) eingeführt (wird aber vom Java-Compiler ignoriert). Aufruf einer beliebigen Methode ist erlaubt, ohne dass geprüft wird, zu welcher Klasse diese Methode gehört, von welchem Typ ihr Returnwert ist oder welche Methodenparameter sie verwendet. Erhöht die Performance für dynamisch typisierte Sprachen. Programmiermethodik - Java Virtual Machine 43 Bytecode in Quellcode umwandeln (1) • Ein Decompiler wandelt Java-Klassendateien in JavaQuellcodedateien zurück. • Reverse Engineering • Decompiler gibt es auch für andere Sprachen, in Java ist aber das Wiederherstellen des ursprünglichen Codes recht einfach. • Bytecode enthält viele Hinweise für den Interpreter. • Ein Decompiler benötigt lediglich die Klassendatei. Einige Decompiler arbeiten auch direkt mit einem jar-Archiv. Aus dem Java-Bytecode für eine Methode baut er dann einen Kontrollfluss-Graphen auf. Der Decompiler versucht Ausdrücke zu erkennen, die bei der Übersetzung bestimmter Sprachkonstrukte entstanden sein müssten. Programmiermethodik - Java Virtual Machine 44 Bytecode in Quellcode umwandeln (2) • Wann ist das legal? Bei eigenem Programm Solange fremde Software nicht verändert wird (?) Nicht mehr, wenn fremde Software als Eigenleistung verkauft wird !!!!!! Programmiermethodik - Java Virtual Machine 45 Jad – Ein Decompiler • Ist ein frei verfügbarer Decompiler Sehr schnell (in C++ geschrieben) Kann auch Bytecode anzeigen. Kann auch „verschleierten“ Code teilweise rekonstruieren. Wird aber nur den gegebenen Code rekonstruieren. Generics sind dann zum Beispiel nicht mehr vorhanden! • Aufruf jad example.class (Ausgabe in example.jad) jad -sjava example.class (Ausgabe in example.java) Weitere Infos: http://www.varaneckas.com/jad • Rückübersetzung erschweren Sogenannte Obfuscater verändern den Code. Decompiler kann dann oft keine richtige Entscheidung treffen. Programmiermethodik - Java Virtual Machine 46 Garbage-Collection Speicherplatzfreigabe • In C free() gibt belegten Speicherplatz frei. Fehleranfällig! • In C++ Konstruktor/Destruktor (Erzeugung, Freigabe) Auch fehleranfällig! • In einem objektorientierten System sollten Objekte verfügbar sein, solange sie benutzt werden. • Die Laufzeitumgebung sollte nicht mehr benutzte Objekte entfernen (und damit den Speicherplatz freigeben). Programmiermethodik - Java Virtual Machine 48 Garbage • Nicht benutzte Objekte Kein anderes Objekt hat eine Referenz auf dieses Objekt. Niemand kann eine Nachricht an dieses Objekt senden. Objekt ist nicht mehr nützlich („Müll“). • Garbage-Collector Ist ein spezieller Prozess. Sammelt periodisch nicht benutzte Objekte ein und gibt den Speicher frei. Erweiterungen werden noch besprochen. • JVM Art der Garbage-Collection ist nicht explizit vorgegeben. Es muss nicht einmal ein Garbage-Collector vorhanden sein. Programmiermethodik - Java Virtual Machine 49 Beispiel Complex c1, c2; c1 = new Complex(); c1 = c2; c1 c2 new Complex() Complex Speicher c1 c2 new Complex() Complex Speicher Garbage!! Verschiedene Ansätze für Garbage-Collection! Programmiermethodik - Java Virtual Machine 50 Garbage-Collection allgemein • 2 Gründe für Garbage-Collection Speicher freigeben JVM kann diese Aufgabe übernehmen (automatisieren). Fragmentierung des Heaps unterbinden bzw. verringern. Für eine neue Allokation wird zusammenhängender Speicher benötigt. Freigabe mehrerer Objekte muss nicht zusammenhängenden freien Speicher freigeben. • Nachteil Zusätzlicher Speicheraufwand CPU-Aufwand wenn der Garbage-Collector anläuft Längere Laufzeit • Unterschiedliche Algorithmen Basierend auf Referenzzähler Tracing-Algorithmen (basierend auf Erreichbarkeitsgraphen) Programmiermethodik - Java Virtual Machine 51 Reference Counting • Jedes Objekt hat einen Zähler rc. Bei der Erzeugung: rc=1 Kommt eine neue Referenz hinzu: rc++ Wird eine Referenz entfernt: rc -Wenn rc==0 dann kann der Garbage-Collector das Objekt einsammeln. • Vorteile Verteilung der Last (aber viel Last!) Gute Lokalität, schnelle Reaktion rc(O1) == 1 Programm O1 P • Nachteile Zusätzlicher Speicherbedarf Zyklen werden nicht erkannt! O2 rc(O2) == 1 O1 und O2 werden nicht mehr von P (im Programm) referenziert. Referenzieren sich aber gegenseitig, d.h. rc==1. Programmiermethodik - Java Virtual Machine 52 Mark-and-Sweep • Definiert Wurzel und überprüft Erreichbarkeit. Wurzel (root set) = Objekte die immer existieren Objekte, die man von der Wurzel aus nicht erreichen kann, werden entfernt. • Mark and Sweep Graph von der Wurzel aus aufbauen. Alle erreichten Objekte markieren. Entferne nicht markierte Objekte. Setze alle markierten Objekte auf nicht-markiert. • Vorteil Kein Problem mit Zyklen • Nachteile Fragmentierung Aufwand proportional zur Heap-Größe Programmiermethodik - Java Virtual Machine 53 Stop-and-Copy (1) • Heap wird in 2 gleich große Bereiche unterteilt. fromspace und tospace • Bei einem Durchlauf werden die Rollen der Bereiche vertauscht. • Bei einem Durchlauf werden die aktuellen Teile vom alten Bereich (fromspace) in den neuen Bereich (tospace) kopiert – Programmvariablen benutzen den neuen Bereich. • Garbage im fromspace wird einfach entfernt. • Im tospace wird beim Kopieren automatisch Fragmentierung unterbunden. Programmiermethodik - Java Virtual Machine 54 Stop-and-Copy (2) 1 • Beispiel frei 2 3 4 5 6 7 8 9 frei unbenutzt unbenutzt unbenutzt frei … frei frei unbenutzt unbenutzt unbenutzt Stop and Copy unbenutzt Stop and Copy • Vorteile Allokation schnell und billig Keine Fragmentierung • Nachteile 50% des Heaps nicht benutzt Langlebige Objekte werden immer wieder kopiert. Programmiermethodik - Java Virtual Machine 55 Generational Collectors (1) • Ein Problem (neben der nicht effizienten Auslastung des Speichers) von Stop-and-Copy ist, dass jedes erreichbare Objekt immer wieder kopiert werden muss. • Dies kann verbessert werden, wenn folgende empirischen Erkenntnisse berücksichtigt werden: Die meisten Objekte haben eine sehr kurze Lebenszeit und werden sehr bald nach der Erzeugung nicht mehr benötigt. Einige Objekte haben eine sehr lange Lebenszeit und sind der Hauptgrund für die Ineffizienz von Stop-and-Copy (werden immer wieder kopiert). Programmiermethodik - Java Virtual Machine 56 Generational Collectors (2) • Vorgehensweise (allgemein) Heap wird in 2 oder mehrere Sub-Heaps unterteilt. Jeder Sub-Heap verwaltet eine „Generation“ von Objekten. Die jüngste Generation wird am öftesten überprüft. Die meisten Objekte werden sehr schnell freigegeben und können eingesammelt werden. Übersteht ein Objekt eine bestimmte Anzahl von Garbage-CollectionDurchläufen, dann wird es in den nächsten Heap verschoben. Je älter die Generation in einem Heap, desto seltener wird dieser Heap überprüft. • Kombination mit herkömmlichen Methoden Mark-and-Sweep Stop-and-Copy Programmiermethodik - Java Virtual Machine 57 Weitere Algorithmen, Methoden etc. • Garbage-Collection kann sehr aufwändig sein. Algorithmus benötigt bestimmte Zeit für das Abarbeiten des Heaps (der Heaps). Laufendes Programm wird angehalten („Stop the world“-Prozess). Großes Problem bei interaktiven Programmen. Sehr großes Problem bei Echtzeitsystemen. • Inkrementelle Anwendung Algorithmus bearbeitet nicht den gesamten Heap (nur Teile davon). Die Zeit für den kleineren Durchlauf kann leichter nach oben beschränkt werden. • Heapgrößen für unterschiedliche Generationen festlegen. Die Zeit für den Durchlauf eines Heaps kann beschränkt werden. Die „älteste“ Generation darf aber nicht beschränkt sein. Für diese muss man sich einen speziellen Algorithmus überlegen. Programmiermethodik - Java Virtual Machine 58 Garbage-Collection und Programmierer • Garbage-Collection ist nicht vorhersagbar! In viele Fällen macht sich die Garbage-Collection nicht bemerkbar. Aber schlecht für Echtzeitsysteme! • Allgemeine Regeln Nur notwendigen Speicher anfordern! Nicht Referenzen horten! Z.B. nicht benötigte Einträge in einem Array auf null setzen! • Aufruf von System.gc() Manchmal sinnvoll Was macht der Garbage-Collector an dieser Stelle? “Calling the gc method suggests that the Java Virtual Machine expend effort toward recycling unused objects in order to make the memory they currently occupy available for quick reuse. When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects.” Programmiermethodik - Java Virtual Machine 59 Objektreferenzen • Unterschiedliche Arten von Referenzen: • Stufen der Erreichbarkeit Strongly reachable Softly reachable Weakly reachable Phantomly reachable Unreachable (bisher besprochen - wenn keine Referenz) Bisher besprochen Garbage-Collector kann Objekte mit solchen Referenzen nicht einsammeln. Programmiermethodik - Java Virtual Machine 60 Soft-Referenzen • Objekte die darüber referenziert werden, werden erst dann eingesammelt, wenn der Speicher knapp wird. • Spezifikation verlangt nur, dass diese Objekte eingesammelt werden, bevor es zu einem OutOfMemory-Error kommt. Soft-Referenzen werden für Caching verwendet. • Ältere Objekte werden zuerst eingesammelt. • Mit der Methode get() bekommt man den Inhalt (das Objekte) der Referenz oder null, wenn das Objekt vom Garbage-Collector eingesammelt wurde • Beispiel (Ausgeben des Inhalts) SoftReference<Integer> i = new SoftReference<Integer>(1000); System.out.println(i.get()); Programmiermethodik - Java Virtual Machine 61 Weak-Referenzen • Objekte die darüber referenziert werden, werden eingesammelt, wenn sie nur mehr über Folgen von Referenzen referenziert werden, die alle zumindest eine Weak-Referenz enthalten. • Sobald der Garbage-Collector anläuft, werden diese Objekte eingesammelt. • Beispiel WeakReference<Integer> i2 = new WeakReference<Integer>(1200); System.out.println(i2.get()); Programmiermethodik - Java Virtual Machine 62 Soft- und Weak-Referenzen (Vergleich) • Beispiel (in Verbindung mit unterschiedlichen Referenzen) SoftReference<Integer> i = new SoftReference<Integer>(1000); WeakReference<Integer> i2 = new WeakReference<Integer>(1200); System.out.println(i.get()); // 1000 System.out.println(i2.get()); // 1200 System.gc(); System.out.println(i.get()); // 1000 System.out.println(i2.get()); // null Programmiermethodik - Java Virtual Machine 63 Phantom-Referenzen • Auf diese kann man nicht mehr zugreifen. • Ermöglichen „sauberes“ Einsammeln der Objekte. • Ähnlich wie finalize-Methode, aber flexibler. • get() liefert immer null. • Anwendungsgebiete sind Abschlussaktionen allgemeiner Art, die sich nicht auf ein bestimmtes Exemplar beziehen und bei denen es ausreicht, festzustellen, dass ein Objekt finalisiert wurde, ohne zu wissen, welches konkrete Objekt es war oder zu welcher Klasse es gehörte. Programmiermethodik - Java Virtual Machine 64 Referenzpfade • Objekte können vom root set ausgehend über mehrere Pfade erreicht werden. • Die schwächste Referenz auf dem stärksten Pfad bestimmt die Erreichbarkeit. Root set PhantomReferenz WeakReferenz SoftReferenz Programmiermethodik - Java Virtual Machine Some Object Erreichbarkeit von Some Object: Soft 65 finalize • Methode finalize() kann in jeder Klasse überschrieben werden (von Object geerbt). • Wird vom Garbage-Collector ausgeführt. Daher kann man nie genau sagen, wann finalize() ausgeführt wird. • Sollte vermieden werden (wenn nicht unbedingt notwendig)! • Sollte möglichst wenig Zeit und Ressourcen verbrauchen! • Allgemeine Form protected void finalize() throws Throwable { try {... /*Freigabe etc.*/ } finally { super.finalize(); } } Programmiermethodik - Java Virtual Machine 66 Garbage-Collection in der JVM (1) • JVM Mehrere Algorithmen Generational Collection Standardeinstellung meist ausreichend • Generations Default-Anordnung sieht ungefähr so aus Programmiermethodik - Java Virtual Machine 67 Garbage-Collection in der JVM (2) • Parameter Garbage-Collection kann parametrisiert werden (bei Aufruf von java). Beispiele -Xms: Anfängliche Heap-Größe -Xmx: Maximale Heap-Größe -XX:MinHeapFreeRatio: Minimales Verhältnis freier/belegter Speicher -XX:MaxHeapFreeRatio: Maximales Verhältnis freier/belegter Speicher Weitere Beispiele: http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html Parameter für Generationen Parameter für unterschiedliche Typen Programmiermethodik - Java Virtual Machine 68 Ausblick • JVM Umfangreiche Spezifikation Programmierer muss sich nur an die Spezifikation halten, kann aber selbst viele Implementierungsentscheidungen treffen. JVM ist mittlerweile recht ausgereift, d.h. recht stabil. • JVM und Java Ursprünglich starke Verbindung zwischen JVM und Java. Mittlerweile gibt es viele andere Sprachen, die JVM-Bytecode erzeugen. • Weitere Informationen Garbage Collection unterliegt ständigen Umbauten: (Java7=G1; Java8=Metaspace) http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html Programmiermethodik - Java Virtual Machine 69 Literatur Literatur • [Venners 2000] Bill Venners, Inside the Java 2 Virtual Machine, McGraw-Hill Companies , 2000, online (ausgewählte Kapitel): http://www.artima.com/insidejvm/ed2/ • [Web 2012] http://jakarta.apache.org/bcel/images/classfile.gif Programmiermethodik - Java Virtual Machine 71