Sie sind hier
E-Book

Java Core Programmierung

Memory Model und Garbage Collection

AutorAngelika Langer, Klaus Kreft
Verlagentwickler.press
Erscheinungsjahr2011
Seitenanzahl250 Seiten
ISBN9783868022629
FormatPDF/ePUB
Kopierschutzkein Kopierschutz/DRM
GerätePC/MAC/eReader/Tablet
Preis19,99 EUR
Für Java-Entwickler sind nicht nur die Sprachelemente der Programmiersprache Java und die umfangreichen Bibliotheken des JDK (Java Development Kit) von Bedeutung; auch die Ablaufumgebung (JVM = Java Virtual Machine) ist relevant für die Software-Entwicklung in Java. Das vorliegende Buch 'Java Core Programmierung' befasst sich mit zwei grundlegenden und wichtigen Aspekten der Java-Ablaufumgebung: dem Java Memory Model (JMM) und der Freispeicherverwaltung (Garbage Collection.) Beim Java Memory Model geht es um die Regeln und Garantien für konkurrierende Zugriffe auf Java-Objekte in Multithread-Programmen. Es werden u.a. folgende Fragestellungen betrachtet: Wann und unter welchen Umständen werden Modifikationen, die ein Thread an einem Java-Objekt gemacht hat, anderen Threads sichtbar? Was genau ist der Effekt von Sprachmitteln wie synchronized, volatile und final? Was ist eine CAS-Operation? Wofür werden atomare Variablen benötigt? Was ist Lock-Free-Programming und warum könnte es mich als Java-Entwickler interessieren? Schon seit Langem ist das Memory Model Bestandteil der Sprachspezifikation von Java. Es ist aber viele Jahre lang wenig beachtet worden. Erst seit Multi-CPU- und Multicore-Plattformen vorherrschend sind, gewinnt das Wissen über die Details des Memory Models an Bedeutung. Detaillierte Kenntnisse des Memory Models sind unerlässlich für alle Java-Entwickler, die Java-Anwendungen für Multi-CPU- und Multicore-Hardware entwickeln und sich mit der Optimierung dieser Anwendungen hinsichtlich Skalierbarkeit und Performanz befassen. Zwar geht es auch beim Thema Freispeicherverwaltung um den 'Speicher', aber mit dem Java Memory Model hat die Garbage Collection nichts zu tun. Es geht vielmehr um die Strategien, die eine virtuelle Maschine anwendet, um den im Programm mit new angeforderten Freispeicher zu verwalten und ihn wieder frei zu geben, wenn er nicht mehr benötigt wird. Virtuelle Maschinen verwenden dazu unterschiedliche Algorithmen. Im vorliegenden Buch werden die Garbage-Collection-Algorithmen der populären HotSpot-JVM von Sun (heute Oracle) betrachtet. Es wird erläutert, warum Generational Garbage Collection sinnvoll ist, wie die HotSpot-JVM den Freispeicher aufteilt und wie die parallelen und konkurrierenden Garbage-Collection-Algorithmen funktionieren. Auch der relativ neue 'Garbage-First' (G1) Collector wird vorgestellt. Ein wesentliches Augenmerk liegt dabei auf dem Tuning dieser zahlreichen Garbage-Collection-Algorithmen. Es lohnt sich beispielsweise zu prüfen, wie viel von der gesamten CPU-Zeit einer Java-Applikation für die Garbage-Collection aufgewendet werden muss. Idealerweise möchte man einen möglichst hohen Durchsatz haben, d.h. es soll viel CPU-Zeit für die Anwendung zur Verfügung stehen und nur wenig Zeit für die Freispeicherverwaltung aufgewendet werden. Auch sollte die Garbage Collection nicht zu störenden Pausen führen, in denen sämtliche Applikations-Threads zum Zwecke der Garbage Collection angehalten werden. Um die Maximierung des Durchsatzes und die Minimierung der Pausenzeiten zu erreichen, bietet die HotSpot-JVM zahlreiche Tuning-Möglichkeiten. Das Buch basiert auf einer Artikelserie, die die Autoren im Java Magazin in den Jahren 2008 bis 2011 veröffentlicht haben. Weitere Beiträge der Artikelreihe sind unter http://www.angelikalanger.com/Articles/EffectiveJava.html zu finden.

Angelika Langer arbeitet als Trainer und Consultant mit eigenem Schulungsprogramm im Bereich der Software-Entwicklung mit Java und C++. Sie ist Autor der Java Generics FAQs, einer Online-Ressource zum Thema Java Generics. Sie ist regelmäßiger Sprecher auf zahlreichen Konferenzen, darunter JavaOne, OOPLSA, JAX, und viele andere. Klaus Kreft arbeitet als Consultant und Performance-Experte im Bereich der Software-Entwicklung mit Java. Sein Interesse gilt komplexen Systemen mit hohen Performance-Anforderungen. Er ist Sprecher auf Fachkonferenzen (JAX, OOP, Ch/Open-Workshop-Tage und diverse JUGs). Gemeinsam sind sie Autor zahlreicher Veröffentlichungen, darunter einer Artikelserie über Core Java Programmierung in der Zeitschrift JavaMagazin und das Buch 'Standard C++ IOStreams and Locales', erschienen bei Addison-Wesley, 2000.

Kaufen Sie hier:

Horizontale Tabs

Leseprobe

2 Das Java-Memory-Modell im Überblick

Im vorangegangenen Kapitel haben wir erläutert, dass man das volatile-Schlüsselwort zur Optimierung verwendet, um die relative teure Synchronisation von konkurrierenden Zugriffen auf gemeinsam verwendete veränderliche Daten zu vermeiden. Dabei haben wir die Sichtbarkeitsregeln erwähnt, die sich im Zusammenhang mit volatile und Synchronisation aus dem Java-Memory-Modell ergeben. In diesem Kapitel wollen wir einen Überblick über Konsistenzregeln für den konkurrierenden Zugriff auf veränderliche Daten geben. Es geht dabei insbesondere um die Atomarität von Zugriffen auf gemeinsam verwendete Daten, deren Reihenfolge und die Sichtbarkeit etwaiger Modifikationen an den Daten.

Im Zusammenhang mit volatile und Synchronisation haben wir bereits den Begriff „Sequential Consistency“ erwähnt. Sequential Consistency ist ein Modell, mit dem sich viele Java-Entwickler das Multithreading in Java vorstellen, obwohl Java gar keine Sequential Consistency unterstützt. Wenn man dennoch so programmiert, als gäbe es Sequential Consistency in Java, können die im letzten Kapitel besprochenen Fehler entstehen.

Das Modell der Sequential Consistency ist ein relativ einfaches Datenkonsistenzmodell. Es ähnelt der Funktionsweise von Multithreading auf einer Single-CPU-Umgebung. Die Vorstellung ist Folgende: Die Threads laufen nicht wirklich parallel, sondern es gibt einen Thread Scheduler, der den einzelnen Threads abwechselnd Zeitscheiben der CPU zuteilt. Ein Thread darf ein paar Operationen ausführen, wird dann verdrängt, es kommt ein anderer Threads dran, der wiederum ein paar Operationen machen darf usw., sodass die einzelnen Threads ihre Operationen in einer sequenziellen Reihenfolge ausführen. Damit verbunden ist die Vorstellung, dass Threads, die später drankommen, Modifikationen im Speicher sehen können, die von Threads vorgenommen wurden, die vorher dran waren. Das ist ein einfaches Konsistenzmodell, das aber in Java nicht unterstützt wird.

Bei einem Konsistenzmodell geht es ganz allgemein (unabhängig von Java) um Regeln für die Zugriffe auf den Speicher. Wenn sich der Programmierer an die Regeln hält, dann gibt ihm das System (in unserem Fall Java und seine virtuelle Maschine) Garantien für die Effekte von Speicherzugriffen, damit der Programmierer weiß, was zur Laufzeit geschehen wird und er die Effekte seiner Speicheroperationen vorhersehen kann. In High-Level-Sprachen wie Java müssen der Compiler und das Laufzeitsystem dafür sorgen, dass die High-Level-Sprachkonstrukte gemäß den Regeln des Konsistenzmodells in Low-Level-Operationen umgesetzt werden.

Auch Java hat ein Konsistenzmodell. Es ist aber nicht das Modell der Sequential Consistency, sondern Java hat ein eigenes Memory-Modell, das als JMM (Java Memory Model) bezeichnet wird. Seine Regeln sind deutlich anders und schwächer als die der Sequential Consistency.

Wir wollen in diesem Beitrag einen Überblick über die Regeln des JMM geben. Das Thema ist ein wenig theoretisch und es ist nicht unmittelbar einsichtig, was all die Regeln für die Praxis der Java-Programmierung bedeuten. Trotzdem wollen wir erst einmal einen Überblick über das Modell als solches geben, ehe wir im Folgenden die einzelnen Aspekte noch einmal näher auf ihre Bedeutung für die Praxis untersuchen.

2.1 Das Java-Memory-Modell

Das Memory-Modell in Java ähnelt einer abstrakten SMP-(Symmetric-Multi-Processing-)Maschine: Die Threads laufen parallel, und konzeptionell haben alle Threads Zugriff auf einen gemeinsamen Hauptspeicher (Main Memory), in dem die gemeinsam verwendeten Variablen abgelegt sind. Daneben hat jeder Thread einen eigenen lokalen Speicherbereich (Cache), in den er Variablen hineinladen und lokal bearbeiten kann. Das Zurückschreiben der lokalen Daten in den Hauptspeicher (Flush) und das Hereinladen von Daten aus dem Hauptspeicher (Refresh) muss nach den Regeln des JMM geschehen. Das JMM beschreibt nun, in welcher Reihenfolge Aktionen passieren und welche Aktionen einen Flush oder Refresh auslösen.

Abbildung 2.1: Abstrakte SMP-Maschine

Eine dieser Regeln besagt zum Beispiel, dass beim Start eines Threads alle relevanten Daten aus dem Hauptspeicher in den lokalen Arbeitsspeicher des Threads geladen werden. Dann darf der Thread mit diesen lokalen Daten arbeiten und muss gar nicht mehr ins Main Memory schauen, weil er die Daten im Cache hat. Am Ende des Threads muss der gesamte lokale Arbeitsspeicher des Threads wieder in den Hauptspeicher zurückgeschrieben werden. Daraus ergibt sich das Verhalten, dass wir auch intuitiv erwarten. Wenn ein Thread mit join auf das Ende eines anderen Threads wartet, kann der wartende Thread sehen, welche Modifikationen der andere, bereits beendete Thread gemacht hat.

Das JMM ist auch wieder nur ein Modell, mit dem sich der Java-Programmierer das Verhalten von Threads in einer JVM erklären kann. In Wirklichkeit muss die virtuelle Maschine die Regeln des JMM auf die Hardware abbilden, die ihr eigenes Hardware-Memory-Modell hat. Die heutigen Multi-Core-Prozessoren arbeiten nicht nur mit einem Cache pro Prozessorkern, sondern teilweise mit mehreren Ebenen von Caches und komplexeren Caching-Mechanismen, als sie das JMM vorsieht. Deshalb fällt der virtuellen Maschine die Aufgabe zu, mit geeigneten Anweisungen an die Hardware die Regeln des JMM zu implementieren.

Abbildung 2.2: Schichten des Memory Modells

2.2 Sichtbarkeitsregeln im JMM

Das Memory-Modell von Java regelt drei Dinge:

  • Atomicity: Welche Operationen sind atomar, das heißt werden nicht durch andere Threads unterbrochen?
  • Ordering: In welcher Reihenfolge passieren die Aktionen?
  • Visibility: Wann werden Modifikationen im Speicher anderen Threads sichtbar gemacht?

Wir wollen an dieser Stelle nicht das komplette Memory-Modell erläutern. Es soll kurz auf die eben genannten Regeln eingegangen werden.

2.2.1 Atomicity

Bei der Atomicity geht es zum Beispiel darum, dass der Zugriff auf Variablen von primitivem Typ (außer long und double) sowie auf Referenzvariablen ununterbrechbar ist. Gleiches gilt für volatile-Variablen (diesmal inklusive long und double). Die Operationen auf atomaren Variablen im Package java.util.concurrent.atomic sind ununterbrechbar. Gleiches gilt für einige der Operationen der Concurrent Collections im Package java.util.concurrent, zum Beispiel die Methode putIfAbsent der ConcurrentMap. Bei Referenzvariablen darf man nicht vergessen, dass stets nur der Zugriff auf die Referenz selbst, das heißt auf die Adresse, atomar ist, nicht etwa der Zugriff auf das referenzierte Objekt. Ansonsten sind die Regeln zur Atomarität relativ einfach zu verstehen.

2.2.2 Ordering

Beim Ordering geht es darum, unter welchen Umständen ein Thread die Effekte von Operationen, die ein anderer Thread ausführt, in der Reihenfolge sehen kann, in der der andere Thread die Operationen vorgenommen hat. Im Allgemeinen ist nämlich ein weitrechendes Re-Ordering erlaubt, an dem sich der Compiler, die virtuelle Maschine und die Hardware beteiligen. Das Re-Ordering führt dazu, dass zwar innerhalb eines Threads klar ist, in welcher Reihenfolge die Effekte der Operationen entstehen, aber ein anderer Thread, der sich das anschaut, sieht die Effekte unter Umständen in einer anderen Reihenfolge, als sie produziert wurden. Es gibt im JMM Regeln für das Ordering, aber sie sind komplex und damit schwer zu verstehen. Deshalb sehen wir uns das Ordering nicht jetzt, sondern in einem späterem Beitrag genauer an.

2.2.3 Visibility

Bei der Visibility geht es darum, ob und wann Modifikationen am Speicher, die ein Thread gemacht hat, den anderen Threads sichtbar werden. Die Sichtbarkeitsregeln des JMM geben eine Reihe von Garantien, von denen wir einige auch schon im letzten Kapitel erwähnt haben:

  • Thread-Start- und -Ende: Der Start eines Threads löst einen Refresh des Thread-lokalen Arbeitsspeichers aus dem Hauptspeicher aus, das Ende des Threads einen Flush. Das entspricht der Intuition. Wenn zum Beispiel ein Thread mit join auf das Ende eines anderen Threads wartet, kann der wartende Thread sehen, welche Modifikationen der andere, bereits beendete Thread an gemeinsam verwendeten Daten gemacht hat.
  • Synchronisation: Der Erhalt eines Locks löst einen Refresh aus, das Freigeben des Locks löst einen Flush aus. Das gilt für die alten impliziten, aber auch für die neuen expliziten Locks. Auch dieses Verhalten entspricht unserer Intuition. Alle Threads, die dasselbe Lock verwenden, durchlaufen die Sequenz der mit diesem Lock synchronisierten Anweisungen nicht parallel, sondern nacheinander. Das heißt es ist klar, dass zunächst ein Thread auf gemeinsam verwendete Daten zugreift und erst danach ein anderer. Da beim Freigeben des Locks der eine Thread alle lokalen Daten in den Hauptspeicher zurückschreiben und der nächste Thread beim Erhalt des Locks seinen lokalen Arbeitsspeicher aus dem Hauptspeicher auffrischen muss, sieht der zweite Thread alle Modifikationen, die der erste Thread an den gemeinsam verwendeten Daten vorgenommen hat.
  • Lese- und Schreibzugriff auf volatile-Variablen: Das Lesen einer volatile-Variablen löst einen Refresh aus, das Modifizieren einer volatile-Variablen löst einen Flush aus. Das bedeutet, dass ein Thread, der den Inhalt...
Blick ins Buch

Weitere E-Books zum Thema: Programmiersprachen - Softwareentwicklung

ASP.NET Shortcut

E-Book ASP.NET Shortcut
Format: PDF

Shortcut-Tipps für ASP.NET-Profis Die neue .NET-Version der Active Server Pages stellt eine Umgebung zur Entwicklung von Web-Applikationen im .NET-Framework bereit. Viele aus der Desktop-…

ASP.NET Shortcut

E-Book ASP.NET Shortcut
Format: PDF

Shortcut-Tipps für ASP.NET-Profis Die neue .NET-Version der Active Server Pages stellt eine Umgebung zur Entwicklung von Web-Applikationen im .NET-Framework bereit. Viele aus der Desktop-…

ASP.NET Shortcut

E-Book ASP.NET Shortcut
Format: PDF

Shortcut-Tipps für ASP.NET-Profis Die neue .NET-Version der Active Server Pages stellt eine Umgebung zur Entwicklung von Web-Applikationen im .NET-Framework bereit. Viele aus der Desktop-…

Programmieren lernen in PHP 5

E-Book Programmieren lernen in PHP 5
Format: PDF

Mit der Version 5 erreicht PHP einen bemerkenswerten Reifegrad, der PHP zu einer festen Größe in der Welt der Webprogrammierung macht. Gerade die leichte Erlernbarkeit macht PHP zur idealen…

Mathematik für Informatiker

E-Book Mathematik für Informatiker
Format: PDF

Die Informatik entwickelt sich in einer unglaublichen Geschwindigkeit. Häufig ist die Mathematik Grundlage von Neuerungen. Deshalb ist sie unverzichtbares Werkzeug jedes Informatikers und Pflichtfach…

Mathematik für Informatiker

E-Book Mathematik für Informatiker
Format: PDF

Die Informatik entwickelt sich in einer unglaublichen Geschwindigkeit. Häufig ist die Mathematik Grundlage von Neuerungen. Deshalb ist sie unverzichtbares Werkzeug jedes Informatikers und Pflichtfach…

Mathematik für Informatiker

E-Book Mathematik für Informatiker
Format: PDF

Die Informatik entwickelt sich in einer unglaublichen Geschwindigkeit. Häufig ist die Mathematik Grundlage von Neuerungen. Deshalb ist sie unverzichtbares Werkzeug jedes Informatikers und Pflichtfach…

Weitere Zeitschriften

Augenblick mal

Augenblick mal

Die Zeitschrift mit den guten Nachrichten "Augenblick mal" ist eine Zeitschrift, die in aktuellen Berichten, Interviews und Reportagen die biblische Botschaft und den christlichen Glauben ...

bank und markt

bank und markt

Zeitschrift für Banking - die führende Fachzeitschrift für den Markt und Wettbewerb der Finanzdienstleister, erscheint seit 1972 monatlich. Leitthemen Absatz und Akquise im Multichannel ...

EineWelt

EineWelt

Lebendige Reportagen, spannende Interviews, interessante Meldungen, informative Hintergrundberichte. Lesen Sie in der Zeitschrift „EineWelt“, was Menschen in Mission und Kirche bewegt Man kann ...

F- 40

F- 40

Die Flugzeuge der Bundeswehr, Die F-40 Reihe behandelt das eingesetzte Fluggerät der Bundeswehr seit dem Aufbau von Luftwaffe, Heer und Marine. Jede Ausgabe befasst sich mit der genaue Entwicklungs- ...