Die Spezifikation der java virtuellen Maschine sieht vor, dass der JVM -Speicher in mehrere Blöcke unterteilt ist, z. B. Haufen, Stapel, Programmzähler, Methodenbereich usw. Bei der Implementierung von Hotspot -JVM wird das Heap -Speicher in drei Teile, die neue Generation, das alte Alter und das anhaltende Band unterteilt. Das persistente Band implementiert den in der Spezifikation angegebenen Methodenbereich, und verschiedene Teile des Speichermodells haben entsprechende Auslöser für Fehler. Als nächstes diskutieren wir es getrennt. Ich glaube, die meisten Entwickler sind auf diesen Fehler gestoßen, und die Gründe für diesen Fehler werden hauptsächlich aus den folgenden Gründen verursacht:
Der JVM -Speicher ist zu klein und das Programm ist nicht eng, was zu viel Müll führt.
Es gibt mehrere häufige Ursachen für Ausnahmen für OutofMemoryError:
Häufige Fehleraufforderungen für diesen Fehler:
Stackoverflowerror
Stack Overflow wirft einen Java.lang.stackoverflowerror -Fehler aus. Dies geschieht, weil die Tiefe des Stapels die maximale Tiefe überschreitet, die die virtuelle Maschine beim Ausführen der Methode zulässt. Diese Situation tritt normalerweise aufgrund von Programmfehlern auf. Zum Beispiel kann das Schreiben einer toten Rekursion diese Situation verursachen. Lassen Sie uns den Speicherüberlauf in dieser Situation durch ein Stück Code simulieren.
import Java.util.*; Java.lang importieren.*; public class oomTest {public void stackoverflowMethod () {StackoverflowMethod (); } public static void main (String ... args) {oomTest oom = new oomTest (); oom.StackoverflowMethod (); }} Wenn Sie den obigen Code ausführen, wird die folgende Ausnahme ausgelöst:
Ausnahme in Thread "Haupt" java.lang.stackoverflowerror bei oomtest.stackoverflowmethod (oomTest.java:6)
Haufen Überlauf (OutofMemoryError: Java Heap Space)
Wenn der Heap -Speicher überläuft, löst die virtuelle Maschine Java.lang.outofMemoryError: Java Heap Space aus. In diesem Fall müssen wir es speziell basierend auf der Dump-Datei analysieren, die bei Überläufen erzeugt wird (-xx: +heapdumponoutofMemoryErrorJVM-Startparameter hinzugefügt werden). Wenn ein solches Problem auftritt, kann es sich um ein Speicherleck oder ein Speicherüberlauf handeln.
Wenn Speicherverletzung ausgelöst wird, müssen wir herausfinden, wie das durchgesickerte Objekt durch GC -Wurzel referenziert wird, und dann die Ursache des Lecks durch die Referenzkette analysieren.
Wenn ein Speicherüberlaufproblem vorhanden ist, liegt dies häufig daran, dass das Programm mehr Speicher als den Speicher benötigt, den wir für die virtuelle Maschine konfigurieren. In diesem Fall können wir das -xmx verwenden, um dieses Problem zu lösen.
Im Folgenden demonstrieren wir den Überlauf dieser Situation durch den folgenden Code:
import Java.util.*; Java.lang importieren.*; public class oomTest {public static void main (String ... args) {list <Byte []> buffer = new ArrayList <Byte []> (); buffer.add (neues Byte [10*1024*1024]); }} Wir führen den obigen Code über den folgenden Befehl aus:
Java -verbose: GC -xmn10m -xms20m -xmx20m -xx:+printgc oomTest
Das Programm gibt die folgenden Informationen ein:
[GC 1180K-> 366K (19456K), 0,0037311 Sekunden] [Full GC 366K-> 330K (19456K), 0,0098740 Sek.] [Full GC 330K-> 292K (19456K), 0,0090244 SECS] In Thread "Main" Java.Lang. Oomtest.main (oomtest.java:7)
Aus den laufenden Ergebnissen können wir erkennen, dass die JVM ein und zweimal ein minderwertiges GC -GC durchgeführt hat. Aus der Ausgabe von Major GC ist ersichtlich, dass die Nutzungsrate des alten Gebiets nach GC 134.000 beträgt und das Byte -Array 10 m beträgt, was sich um größer ist als der Raum der alten Generation, sodass eine Ausnahme ausgelöst wird. Wenn -xms21m und -xmx21m angepasst werden, wird der GC -Vorgang nicht ausgelöst und es wird keine Ausnahme geben.
Durch das obige Experiment wurde eine Schlussfolgerung von der Seite verifiziert: Wenn das Objekt größer als die verbleibende Erinnerung an die neue Generation ist, wird es direkt in das Alter platziert. Wenn die verbleibende Erinnerung an das Alter immer noch nicht niedergeschlagen werden kann, wird die Müllsammlung ausgelöst. Wenn es nach der Sammlung immer noch nicht niedergeschlagen werden kann, wird eine Ausnahme über den Speicherüberlauf ausgelöst.
Permgenraum
Wir wissen, dass Hotspot JVM den Methodenbereich in der Spezifikation "Virtual Machine Java Virtual Machine" durch persistente Bänder implementiert und der konstante Laufzeitpool im Methodenbereich gespeichert ist. Daher kann der persistente Bandüberlauf der Überlauf des Laufzeit konstanten Pools sein, oder die im Methodenbereich gespeicherten Klassenobjekte werden nicht rechtzeitig recycelt oder der von Klasseninformationen besetzte Speicher überschreitet unsere Konfiguration. Wenn das Persistenzband überläuft, wird Java.lang.outofMemoryError: Permgen -Raum geworfen.
Ich kann dieses Problem in den folgenden Szenarien bei der Arbeit erleben.
Bei der Verwendung einiger Anwendungsserver werden die Hot Deployment mehrmals auf die Hot Deployment begegnen und feststellen, dass Speicherüberläufe. Dies liegt daran, dass nach jeder Hot -Bereitstellung die ursprüngliche Klasse nicht deinstalliert wurde.
Wenn die Anwendung selbst größer ist und mehr Klassenbibliotheken beinhaltet, kann dieses Problem auch auftreten, wenn der Speicher, den wir dem persistenten Band zuordnen (von -xx: permsize und -xx: maxpermsize) relativ gering ist.
Einige Frameworks von Drittanbietern wie Spring und Hibernate implementieren einige verbesserte Funktionen über die Bytecode-Generationstechnologie (wie CGGLIB), für die möglicherweise ein größerer Methodenbereich für dynamisch generierte Klassendateien gespeichert werden muss.
Wir wissen, dass Streichkonstanten in Java in einem konstanten Pool platziert werden. Wenn die Methode von String.Intern () ausgeführt wird, wird überprüft, ob Objekte, die dieser Zeichenfolge entsprechen, im konstanten Pool gespeichert werden. Wenn es vorhanden ist, geben Sie direkt einen Verweis auf das Objekt im konstanten Pool zurück. Wenn es nicht vorhanden ist, fügen Sie diese Zeichenfolge zuerst zum konstanten Pool hinzu und geben Sie dann den Verweis auf die Zeichenfolge zurück. Anschließend können wir den Überlauf des konstanten Bereichs während der Laufzeit über die methode string.intern simulieren. Lassen Sie uns diese Situation durch den folgenden Code simulieren:
import Java.util.*; Java.lang importieren.*; public class oomTest {public static void main (String ... args) {list <string> list = new ArrayList <string> (); while (true) {list.add (uUid.randomuuid (). toString (). praktikum ()); }}}Wir führen den obigen Code über den folgenden Befehl aus:
Java -Verbose: GC -xmn5m -xms10m -xmx10m -xx: maxpermSize = 1m -xx:+printgc oomTest
Die Eingabe nach dem Laufen ist in der folgenden Abbildung dargestellt:
Ausnahme im Thread "Haupt" java.lang.outofMemoryError: Permgen -Raum bei java.lang.string.intern (native Methode) bei oomtest.main (oomtest.java:8)
Über den obigen Code simulierten wir den konstanten Poolüberlauf während der Laufzeit erfolgreich. Aus dem Permgen -Raum in der Ausgabe können wir erkennen, dass das persistente Band tatsächlich überfüllt ist, was auch die Aussage überprüft, dass der Hotspot JVM den Methodenbereich durch persistierendes Band implementiert, wie bereits erwähnt.
OutofMemoryError: Naher nativer Thread erstellen
Schauen wir uns schließlich den Fehler an, den Java.lang.outofMemoryError: Natvie -Thread erstellen kann. In diesem Fall wird es normalerweise durch die folgenden zwei Situationen verursacht:
Die Anzahl der vom Programm erstellten Threads übersteigt die Betriebssystemlimit. Für Linux -Systeme können wir diese Einschränkung durch Ulimit -u betrachten.
Der an die virtuelle Maschine zugeordnete Speicher ist zu groß und führt zu einem zu wenig nativen Speicher beim Erstellen von Threads. Wir alle wissen, dass das Betriebssystem eine Grenze für den Speicher jedes Prozesses hat. Bei der Start von JVM ist es gleichwertig, einen Prozess zu starten. Wenn einer unserer Prozesse 4G Speicher einnimmt, ist der verbleibende Speicher, der durch die folgende Formel berechnet wird, der Speicher, der beim Erstellen eines Thread -Stapels verwendet werden kann. Gesamt verfügbarer Speicher für Thread Stack = 4G- (Wert von -xmx)-(-xx: Wert von maxpermSize)-Der vom Programmzähler besetzte Speicher wird durch die obige Formel angezeigt, dass je größer die Werte von -xmx und Maxpermsize sind, desto kleiner der verfügbare Speicherplatz für den Thread-Stapel. Wenn die vom Parameter -xSS konfigurierte Stapelkapazität unverändert bleibt, desto kleiner ist die Anzahl der erstellten Threads. Wenn es aufgrund dieser Situation unmöglich ist, nativen Thread zu erstellen, erhöhen wir daher entweder den durch den Prozess besetzten Gesamtspeicher oder reduzieren die XMX oder -xSS, um den Zweck zu erreichen, mehr Threads zu erstellen.
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.