1. Vorwort
Java ist eine Cross-Hardware-Plattform-objektorientierte Programmiersprache auf hoher Ebene. Java -Programme werden auf Java Virtual Machines (JVMS) ausgeführt und den Speicher durch JVMS verwalten. Dies ist der größte Unterschied zu C ++. Obwohl der Speicher von JVMS verwaltet wird, müssen wir auch verstehen, wie JVM den Speicher verwaltet. Es gibt nicht nur einen JVM, und derzeit gibt es Dutzende virtueller Maschinen, sondern ein virtuelles Maschinendesign, das der Spezifikation entspricht, muss der "Spezifikation" Java Virtual Machine "folgen. Dieser Artikel basiert auf der Beschreibung der virtuellen Hotspot -Maschine und wird erwähnt, wenn es Unterschiede zu anderen virtuellen Maschinen gibt. In diesem Artikel wird hauptsächlich beschrieben, wie das Speicher in JVM verteilt wird, wie Objekte des Java -Programms gespeichert und zugegriffen werden, und mögliche Ausnahmen in verschiedenen Speicherbereichen.
2. Speicherverteilung (Region) in JVM
Bei der Ausführung von Java -Programmen unterteilt der JVM den Speicher in mehrere verschiedene Datenbereiche für die Verwaltung. Diese Bereiche haben unterschiedliche Funktionen, Schöpfungs- und Zerstörungszeiten. Einige Bereiche werden zugewiesen, wenn der JVM -Prozess gestartet wird, während andere mit dem Lebenszyklus des Benutzer -Threads (dem Thread des Programms selbst) zusammenhängen. Gemäß der JVM -Spezifikation sind die vom JVM verwalteten Speicherbereiche in die folgenden Laufzeitbereiche unterteilt:
1. Virtueller Maschinenstapel
Dieser Speicherbereich ist vom Thread privat und wird erstellt, wenn der Thread beginnt und zerstört wird, wenn er zerstört wird. Das Speichermodell für die Ausführung von Java -Methoden, die vom Virtual Machine Stack beschrieben wurden: Jede Methode erstellt zu Beginn der Ausführung einen Stapelrahmen (Stack -Frame), mit dem lokale variable Tabellen, Operand -Stapel, dynamische Links, Methodenabschlüsse usw. gespeichert werden.
Wie der Name schon sagt, handelt es sich bei der lokalen Variablen -Tabelle um einen Speicherbereich, der lokale Variablen speichert: Sie speichert die grundlegenden Datentypen (8 Java -Grunddatentypen), Referenztypen und Abgabeadressen, die während der Compiler -Periode gefunden werden können. Die langen und doppelten Typen, die 64 Bits belegen, belegen 2 lokale variable Raum, und andere Datentypen belegen nur 1; Da die Typgröße ermittelt wird und die Anzahl der Variablen während der Kompilierungsperiode bekannt sein kann, hat die lokale Variable -Tabelle eine bekannte Größe, wenn sie erstellt wird. Dieser Teil des Speicherraums kann während der Kompilierungsperiode zugewiesen werden, und es ist nicht erforderlich, die lokale variable Tabellengröße während des Methodenlaufs zu ändern.
In der Spezifikation der virtuellen Maschine werden für diesen Speicherbereich zwei Ausnahmen angegeben:
1. Wenn die vom Thread angeforderte Stapeltiefe größer ist als die zulässige Tiefe (?), Wird StackOverflowError ausgelöst.
2. Wenn sich die virtuelle Maschine dynamisch ausdehnen kann und die Ausdehnung nicht für ausreichende Speicher angewendet werden kann, wird eine Ausnahme OutOfMemory ausgelöst.
2. Lokaler Methodenstapel
Der lokale Method-Stack ist ebenfalls Thread-privat, und seine Funktion entspricht fast dem virtuellen Maschinenstack: Der Virtual Machine Stack bietet In- und Out-Stack-Dienste für die Ausführung von Java-Methoden, während der lokale Methode-Stack Dienste für die virtuelle Maschine zur Ausführung native Methoden bietet.
In der Spezifikation der virtuellen Maschine gibt es keine obligatorische Vorschriften für die Implementierungsmethode des lokalen Method -Stacks und kann von der spezifischen virtuellen Maschine frei implementiert werden. Die virtuelle Hotspot -Maschine kombiniert direkt den virtuellen Maschinenstapel und den lokalen Methodenstapel in einen. Damit andere virtuelle Maschinen diese Methode implementieren können, können Leser relevante Informationen abfragen, wenn sie interessiert sind.
Wie der Virtual Machine Stack wirft auch der lokale Method -Stack StackOverflowError和OutOfMemory -Ausnahmen.
3. Programmrechner
Der Programmrechner ist auch ein privater Speicherbereich von Threads. Es kann als Zeilennummernanzeige (auf einen Anweisungen verweist) für Threads angesehen werden, um Bytecode auszuführen. Wenn Java ausgeführt wird, erhält der nächste Anweisungen, der ausgeführt wird, indem der Wert des Zählers geändert wird. Die Ausführungsaufträge von Zweigen, Schleifen, Sprüngen, Ausnahmebehandlung, Fadenwiederherstellung usw. Das Multithreading einer virtuellen Maschine wird erreicht, indem die Ausführungszeit des Prozessors umschaltet und die Prozessorausführungszeit zugewiesen wird. Der Prozessor (ein Kern für einen Multi-Core-Prozessor) kann jeweils nur einen Befehl ausführen. Nachdem der Thread die Schaltung durchführen kann, muss er daher in die richtige Ausführungsposition wiederhergestellt werden. Jeder Thread verfügt über einen unabhängigen Programmrechner.
Bei der Ausführung einer Java -Methode zeichnet der Programmrechner auf die Adresse des Bytecode -Befehls auf, den der aktuelle Thread ausführt. Wenn die native Methode ausgeführt wird, ist der Wert dieses Taschenrechners undefiniert. Dies liegt daran, dass das Threadmodell des Hotspot Virtual Machine ein nationales Threadmodell ist, dh jeder Java -Thread kartiert direkt den Thread des Betriebssystems (Betriebssystem). Bei der Ausführung der nativen Methode wird sie direkt vom Betriebssystem ausgeführt. Der Wert dieses Zählers der virtuellen Maschine ist nutzlos; Da dieser Taschenrechner ein Speicherbereich mit sehr kleinem Raum ist, erfordern keine Expansion. Es ist der einzige Bereich in der Spezifikation für virtuelle Maschine, in der keine Ausnahme OutOfMemoryError angegeben ist.
4. Heap -Speicher (Heap)
Der Java Heap ist ein Speicherbereich, der von Threads geteilt wird. Es kann gesagt werden, dass es sich um den größten Speicherbereich handelt, der von der virtuellen Maschine verwaltet wird und beim Start der virtuellen Maschine erstellt wird. Der Java Heap -Speicher speichert hauptsächlich Objektinstanzen, und fast alle Objektinstanzen (einschließlich Arrays) werden hier gespeichert. Daher ist dies auch der Hauptspeicherbereich der Müllsammlung (GC). Der Inhalt über GC wird hier nicht beschrieben;
Gemäß der Spezifikation der virtuellen Maschine kann Java Heap -Speicher im diskontinuierlichen physischen Speicher sein. Solange es logisch kontinuierlich ist und die Raumausdehnung nicht begrenzt ist, kann es entweder eine feste Größe oder ein ausgedehnter Baum sein. Wenn der Heap -Speicher nicht über genügend Platz verfügt, um die Instanzzuordnung zu vervollständigen und nicht erweitert werden kann, wird eine Ausnahme OutOfMemoryError ausgelöst.
5. Methodenbereich
Der Methodenbereich ist der Speicherbereich, der von Threads geteilt wird, genau wie der Heap -Speicher, die Typinformationen, Konstanten, statische Variablen, Code, die während der Instant -Kompilierungsperiode und anderen Daten kompiliert wurden. Die Spezifikation für virtuelle Maschine enthält nicht zu viele Einschränkungen für die Implementierung des Methodenbereichs. Wie bei Heap -Speicher muss nicht kontinuierlicher physischer Speicherplatz erstellt werden. Die Größe kann fest oder skalierbar sein und kann auch ausgewählt werden, um keine Müllsammlung zu implementieren. Wenn der Methodenbereich die Anforderungen an die Speicherzuweisung nicht erfüllen kann, wird die Ausnahme OutOfMemoryError ausgelöst.
6. Direkter Speicher
Der direkte Speicher ist nicht Teil des verwalteten Speichers der virtuellen Maschine, aber dieser Teil des Speichers kann weiterhin häufig verwendet werden. Wenn Java-Programme native Methoden verwenden (z. B. NIO, NIO, hier sind keine Beschreibungen angegeben), kann das Speicher direkt außerhalb der Härte zugewiesen werden, aber der Gesamtspeicherraum ist begrenzt, und es wird auch nicht genügend Speicher geben, und es wird auch eine Ausnahme OutOfMemoryError ausgelöst.
2. Zugang zum Speichern von Instanzobjekten Speicher
Der erste Punkt oben hat eine allgemeine Beschreibung des Speichers in jedem Bereich der virtuellen Maschine. Für jeden Bereich gibt es Probleme damit, wie Daten erstellt, angelegt und zugegriffen werden. Verwenden wir den am häufigsten verwendeten Heap -Speicher als Beispiel, um über diese drei Aspekte basierend auf Hotspot zu sprechen.
1. Instanzobjekterstellung
Wenn die virtuelle Maschine einen neuen Befehl ausführt, findet sie zunächst zuerst die Klassensymbolreferenz des Erstellungsobjekts aus dem konstanten Pool und beurteilt, ob die Klasse geladen und initialisiert wurde. Wenn es nicht geladen ist, wird der Prozess der Klassenlastinitialisierung ausgeführt (die Beschreibung wird hier nicht über die Klassenbelastung erstellt). Wenn diese Klasse nicht gefunden werden kann, wird eine gemeinsame Ausnahme ClassNotFoundException ausgelöst.
Nach dem Laden der Klasse wird der physische Speicher (Heap -Speicher) dem Objekt tatsächlich zugewiesen. Der vom Objekt erforderliche Speicherplatz wird durch die entsprechende Klasse bestimmt. Nach dem Laden des Unterrichts ist der Speicherplatz, der vom Objekt dieser Klasse benötigt wird, festgelegt. Die Zuordnung des Speicherraums für das Objekt ist gleichbedeutend mit der Aufteilung eines Stücks vom Haufen und der Zuweisung dieses Objekts.
Ob der Speicherraum kontinuierlich ist (zugewiesen und nicht zugewiesen werden in zwei vollständige Teile unterteilt), wird er in zwei Möglichkeiten unterteilt, um Gedächtnis zuzuweisen:
1. Kontinuierlicher Speicher: Ein Zeiger wird als Trennpunkt zwischen zugewiesenem und nicht zugewiesenem Speicher verwendet. Die Objektspeicherzuweisung erfordert nur, dass der Zeiger die Speicherplatzgröße in das nicht zugewiesene Speichersegment verschiebt. Diese Methode wird als "Zeigerkollision" bezeichnet.
2. Diskontinuierlicher Speicher: Die virtuelle Maschine muss eine Liste verwalten (aufzeichnen), die diese Speicherblöcke im Haufen aufzeichnet, die nicht zugewiesen werden. Wählen Sie bei der Zuweisung des Objektspeichers einen Speicherbereich mit geeigneter Größe aus, um ihn dem Objekt zuordnen, und aktualisieren Sie diese Liste. Diese Methode wird als "freie Liste" bezeichnet.
Die Zuteilung des Objektspeichers tritt auch auf Parallelitätsprobleme auf. Die virtuelle Maschine verwendet zwei Lösungen, um dieses Problem der Threadsicherheit zu lösen: Verwenden Sie zunächst CAS (Compare and Set)+, um die Atomizität des Allokationsbetriebs zu identifizieren und wiederzuholen. Zweitens wird die Speicherzuweisung in verschiedene Räume entsprechend den Threads unterteilt, dh jeder Thread hat ein Stück Thread-privat-Speicher im Heap vorgewiesen, der als lokal-zu-zugeerdigten Puffer (TLAB) bezeichnet wird. Wenn dieser Thread Speicher zuweisen will, wird er direkt aus dem TLAB zugewiesen. Nur wenn der TLAB des Fadens nach erneuter Allosion zugewiesen wird, kann der synchrone Vorgang vom Haufen zugewiesen werden. Diese Lösung reduziert effektiv die Parallelität des HEAP -Speichers der Objektzuweisung zwischen Threads. Ob die virtuelle Maschine TLAB verwendet, wird durch den JVM -Parameter -xx eingestellt: +/- usetlab.
Nach Abschluss der Speicherzuweisung initialisiert die virtuelle Maschine zusätzlich zu den Objekt -Header -Informationen den zugewiesenen Speicherplatz auf Null, um sicherzustellen, dass die Felder der Objektinstanz direkt an den Nullwert verwendet werden können, der dem Datentyp entspricht, ohne Werte zuzuweisen. Führen Sie dann die Init -Methode aus, um die Initialisierung gemäß dem Code zu vervollständigen, bevor ein Instanzobjekt abgeschlossen ist.
2. Das Layout von Objekten im Speicher
In der virtuellen Hotspot -Maschine sind Objekte in drei Teilen im Speicher unterteilt: Objektkopf, Instanzdaten sowie Ausrichtung und Füllung:
Der Objektheader ist in zwei Teile unterteilt: Ein Teil davon speichert die Objekt -Laufzeitdaten, einschließlich Hash -Code, Erzeugung von Müllsammlungen, Objektsperrstatus, Thread -Holding -Sperre, vorgespannte Gewinde -ID, voreingenommener Zeitstempel usw.; In 32-Bit- und 64-Bit-virtuellen Maschinen befindet sich dieser Teil der Daten 32-Bit bzw. 64-Bit; Da es viele Laufzeitdaten gibt, reicht 32-Bit oder 64-Bit nicht aus, um alle Daten vollständig zu speichern. Daher ist dieser Teil so konzipiert, dass Laufzeitdaten in einem nicht fixierten Format gespeichert werden, aber verschiedene Bits verwendet, um Daten gemäß dem Status des Objekts zu speichern. Der andere Teil speichert den Objekttypzeiger und zeigt auf die Klasse dieses Objekts, dies ist jedoch nicht erforderlich, und die Klassenmetadaten des Objekts müssen nicht unbedingt mit diesem Teil des Speichers bestimmt werden (er wird unten diskutiert).
Instanzdaten sind der Inhalt verschiedener Datenarten, die vom Objekt definiert wurden, und die von diesen Programmen definierten Daten werden nicht in der definierten Reihenfolge gespeichert. Sie werden in der Reihenfolge der Richtlinien und Definitionen der virtuellen Maschine bestimmt: Long/Double, Int, Short/CHAR, Byte/Boolean, OOP (gewöhnlicher Objektponint) . Es ist zu erkennen, dass die Richtlinien gemäß der Anzahl der Platzhalter des Typs zugewiesen werden, und dieselben Typen vergeben Speicher zusammen. und unter der Zufriedenheit dieser Bedingungen geht der Reihenfolge der übergeordneten Klassenvariablen der Unterklasse voraus;
Der Teil des Objekts füllte sich nicht unbedingt. Es spielt nur eine Rolle bei der Ausrichtung der Soldaten. Im Hotspot wird Virtual Machine Memory Management in Einheiten von 8 Bytes verwaltet. Wenn der Speicher zugewiesen wird, ist die Objektgröße daher nicht ein Vielfaches von 8 und die Ausrichtungsfüllung wird abgeschlossen.
3.. Objektzugriff <br /> Im Java -Programm erstellen wir ein Objekt, und tatsächlich erhalten wir eine Referenztypvariable, über die wir tatsächlich eine Instanz im Heap -Speicher betreiben. In der Spezifikation der virtuellen Maschine wird nur festgelegt, dass der Referenztyp eine Referenz ist, die auf das Objekt zeigt, und nicht angibt, wie diese Referenz die Instanzen im Haufen lokalisiert und zugreift. Derzeit gibt es in Mainstream -Virtual -Maschinen zwei wichtige Möglichkeiten, um den Objektzugriff zu implementieren:
1. Handlungsmethode: Ein Region wird als Griffpool in den Heap -Speicher unterteilt. Die Referenzvariable speichert die Handlungsadresse des Objekts und das Handle speichert die spezifischen Adressinformationen des Beispielobjekts und des Objekttyps. Daher kann der Objektkopf den Objekttyp nicht enthalten:
2. Direkter Zugriff auf Zeiger: Der Referenztyp speichert direkt die Adressinformationen des Instanzobjekts im Heap. Dies erfordert jedoch, dass das Layout des Instanzobjekts den Objekttyp enthalten muss:
Diese beiden Zugriffsmethoden haben ihre eigenen Vorteile: Wenn die Objektadresse geändert wird (Speichersortierung, Müllsammlung), muss die Referenzvariable nicht geändert werden, sondern nur der Objektadresswert im Handle wird geändert. Während der Verwendung der Zeiger -Direktzugriffsmethode müssen alle Referenzen dieses Objekts geändert werden. Die Zeigermethode kann jedoch einen Adressierungsvorgang reduzieren, und bei einer großen Anzahl von Objektzugriffszugriffe sind die Vorteile dieser Methode offensichtlicher. Die virtuelle Hotspot -Maschine verwendet diese Methode für den Direktzugriff.
3. Ausnahme von Laufzeitspeicher
Es gibt zwei Hauptausnahmen, die beim Laufen im Java -Programm auftreten können: outofMemoryError und stackoverflowerror; Was wird in diesem Speicherbereich passieren? Wie bereits kurz erwähnt, werden außer dem Programmzähler andere Speicherbereiche auftreten. Dieser Abschnitt zeigt hauptsächlich die Ausnahmen in jedem Speicherbereich über Instanzcode, und viele häufig verwendete Virtual Machine Startup -Parameter werden verwendet, um die Situation besser zu erklären. (Wie man das Programm mit Parametern ausführt, wird hier nicht beschrieben)
1. Java Heap Speicherüberlauf
Heap -Speicherüberlauf tritt auf, wenn Objekte erstellt werden, nachdem die Heap -Kapazität die maximale Haufenkapazität erreicht hat. Im Programm werden Objekte kontinuierlich erstellt, und diese Objekte sind garantiert, dass sie nicht Müll gesammelt haben:
/** * Parameter Virtual Machine: * -xms20m Minimum Heap -Kapazität * -xmx20m Maximal Heap -Kapazität * @Author Hwz * */public class HeadoutofMemoryError {public static void Main (String [] Argumente) {// Container, um das Objekt zu speichern, um sicherzustellen, dass das Objekt kein Mülfrüchten ist. ArrayList <eadoutOfMemoryError> (); while (true) {// kontinuierlich Objekte erstellen und zum Container listtoholdObj.add (neuer HeadoutofMemoryError ()); }}} Sie können virtuelle Maschinenparameter hinzufügen :-XX:HeapDumpOnOutOfMemoryError . Lassen Sie beim Senden einer OOM -Ausnahme die virtuelle Maschine die Snapshot -Datei des aktuellen Heaps abgeben. Sie können dieses Problem mit der Segmentierung des Dateiworts in Zukunft verwenden. Dies wird nicht ausführlich beschrieben. Ich werde ein Blog schreiben, um das ausführliche mit dem MAT -Tool zu beschreiben, um Speicherprobleme zu analysieren.
2. Virtual Machine Stack und lokaler Methodenstapelüberlauf
In der virtuellen Hotspot -Maschine werden diese beiden Methodenstapel nicht zusammen implementiert. Nach der Spezifikation der virtuellen Maschine treten diese beiden Ausnahmen in diesen beiden Speicherbereichen auf:
1. Wenn der Thread die Stapeltiefe größer als die maximale Tiefe der virtuellen Maschine anfordert, werfen Sie eine Stackoverflowerror -Ausnahme aus.
2. Wenn die virtuelle Maschine bei Erweiterung des Stapelraums keinen großen Speicherplatz anwenden kann, wird eine Ausnahme von OutofMemoryError ausgelöst.
Es gibt tatsächlich Überlappungen zwischen diesen beiden Situationen: Wenn der Stapelraum nicht zugeteilt werden kann, ist es unmöglich zu unterscheiden, ob das Gedächtnis zu klein ist oder die gebrauchte Stapeltiefe zu groß ist.
Verwenden Sie zwei Möglichkeiten, um den Code zu testen
1. Verwenden Sie den Parameter -XSS, um die Stapelgröße zu reduzieren, aufzunehmen, eine Methode unendlich rekursiv und erhöhen Sie die Stapeltiefe unendlich:
/** * Parameter Virtual Machine: <br> * -XSS128K Stack -Kapazität * @Author hwz * */public class stackoverflowerror {private int stackdeep = 1; / *** Infinite Rekursion, unendlich vergrößern die Anrufstapel -Tiefe*/ public void reursiveInvoke () {StackDeep ++; recursiveInvoke (); } public static void main (String [] args) {stackoverflowerror soe = new stackoverflowerror (); try {Soe.RecursiveInvoke (); } catch (throwable e) {System.out.println ("stack Deep =" + soe.stackDeep); werfen e; }}} Eine große Anzahl lokaler Variablen ist in der Methode definiert. Die Länge der lokalen Variablentabelle im Methodenstapel wird auch unendlich rekursiv bezeichnet:
/** * @Author hwz * * */public class stackoomeError {private int stackdeep = 1; / *** Definieren Sie eine große Anzahl lokaler Variablen, erhöhen Sie die lokale variable Tabelle im Stapel* Infinite Rekursion, erhöhen Sie unendlich die Tiefe des Anrufstacks*/ public void recursiveInvoke () {Double I; Doppel I2; // ..... Die große Anzahl von Variablendefinitionen wird hier weggelassen, StackDeep ++; recursiveInvoke (); } public static void main (String [] args) {stackoomeError soe = new stackoomeError (); try {Soe.RecursiveInvoke (); } catch (throwable e) {System.out.println ("stack Deep =" + soe.stackDeep); werfen e; }}}Der obige Code -Test zeigt, dass unabhängig davon, ob der Frame -Stapel zu groß ist oder die Kapazität der virtuellen Maschine zu klein ist. Wenn der Speicher nicht zugewiesen werden kann, wird alle Stackoverflowerror geworfen.
3.. Methodenbereich und Laufzeitkonstante Poolüberlauf
Hier beschreiben wir zunächst die praktische Stringmethode: Wenn der String Constant Pool bereits eine Zeichenfolge enthält, die diesem String -Objekt entspricht, wird ein String -Objekt zurückgegeben, das diese Zeichenfolge darstellt. Fügen Sie dieses String -Objekt ansonsten dem konstanten Pool hinzu und geben Sie eine Referenz in dieses String -Objekt zurück. Durch diese Methode fügt sie dem konstanten Pool kontinuierlich ein String -Objekt hinzu, was zu Überlauf führt:
/** * Parameter Virtual Machine: <br> * -xx: permSize = 10 m dauerhafte Flächengröße * -xx: MaxpermSize = 10 m Maximale Kapazität von Dauergebiet * @author hwz * * */public class runTimeConstancePooloom {öffentlich statische VOID -Hauptstreich [] Argumente). ArrayList <string> (); // Verwenden Sie die Methode String.intern, um das Objekt des konstanten Pools für (int i = 1; true; i ++) {list.add (String.Valueof (i) .intern ()) hinzuzufügen; }}}Dieser Testcode überfließt jedoch während des Laufzeit konstanten Pools in JDK1.7, aber er wird in JDK1.6 passieren. Schreiben Sie aus diesem Grund einen anderen Testcode, um dieses Problem zu überprüfen:
/** * string.intern -Methode wird unter verschiedenen jdks getestet * @author hwz * */public class StringInternTest {public static void main (string [] args) {String str1 = new StringBuilder ("test"). Append ("01"). ToString (); System.out.println (str1.intern () == str1); String str2 = new StringBuilder ("test"). Append ("02"). ToString (); System.out.println (str2.intern () == str2); }} Die Ergebnisse des Laufens unter JDK1.6 sind: falsch, falsch;
Das Ergebnis des Laufens unter JDK1.7 ist: wahr, wahr;
Es stellt sich heraus, dass in JDK1.6 die Praktikum () die erste aufgetroffene String -Instanz der dauerhaften Generation kopiert, was wiederum ein Verweis auf die Instanz in der dauerhaften Generation ist, und die von StringBuilder erstellten String -Instanzen sind auf dem Haufen, sodass sie nicht gleich sind.
In JDK1.7 kopiert die praktische () -Methode die Instanz nicht, sondern zeichnet nur die Referenz der ersten Instanz auf, die im konstanten Pool angezeigt wird. Daher ist die vom Praktikanten zurückgegebene Referenz dieselbe wie die von StringBuilder erstellte Instanz, sodass sie wahr zurückgibt.
Daher hat der Testcode für einen konstanten Poolüberlauf keine konstante Poolüberlaufausnahme, kann jedoch eine unzureichende Ausnahme des Heap -Speichers nach kontinuierlichem Laufen aufweisen.
Anschließend müssen Sie den Überlauf des Methodenbereichs testen und den Methodenbereich weiter hinzufügen, z. B. Klassennamen, Zugriffsmodifikatoren, konstante Pools usw. Wir können das Programm eine große Anzahl von Klassen laden lassen, um den Methodenbereich kontinuierlich zu füllen, was zum Überlauf führt. Wir verwenden CGlib, um die Bytecode direkt zu manipulieren, um eine große Anzahl dynamischer Klassen zu erzeugen:
/** * Methode Area Memory Overflow Test Class * @Author hwz * */public class methodAreaoom {public static void main (String [] args) {// Verwenden Sie GCLIB, um Unterklassen in unendlichem, während (true) {Enhancer Enhancer = new Enhancer () zu erstellen; Enhancer.SetsuperClass (MaoomClass.Class); Enhancer.SetUsecache (Falsch); Enhancer. Enhancer.create (); }} statische Klasse MaoomClass {}} Durch die VisualVM -Beobachtung können wir sehen, dass die Anzahl der JVM -geladenen Klassen in einer geraden Linie mit Pergen verwendet wird:
4. Direkter Speicherüberlauf
Die Größe des direkten Speichers kann über die Parameter der virtuellen Maschine eingestellt werden : -xx: maxdirectMemorySize . Um einen direkten Speicherüberlauf zu erzielen, müssen Sie nur kontinuierlich einen direkten Speicher anwenden. Das Folgende entspricht dem direkten Speicher -Cache -Test in Java nio:
/** * Parameter Virtual Machine: <br> * -xx: maxdirectMemorySize = 30m Direktspeichergröße * @author hwz * */public class lirectMemoryoom {public static void main (String [] args) {list <puffer> buffer = new ArrayList <Buffer <puffer> (); int i = 0; while (true) {// Drucken Sie das aktuelle System.out.println (++ i); // Direkter Speicherkonsum durch kontinuierliche Bewerbung für den Direktpufferspeicherverbrauch im Cache -Puffer.ADD (bytebuffer.allocatedirect (1024*1024)); // Accounting 1m jedes Mal}}} In der Schleife wird jedes Mal, java.lang.OutOfMemoryError: Direct buffer memory 1M direkter Speicher angewendet wird
4. Zusammenfassung
Das obige ist der gesamte Inhalt dieses Artikels. Dieser Artikel beschreibt hauptsächlich die Layoutstruktur von Speicher-, Objektspeicher- und Speicherausnahmen, die in verschiedenen Speicherbereichen im JVM auftreten können. Das Haupt-Nachschlagewerk "Tiefes Verständnis von Java Virtual Machine (zweite Ausgabe)". Wenn es etwas Falsches gibt, weisen Sie bitte in den Kommentaren darauf hin. Vielen Dank für Ihre Unterstützung für Wulin.com.