ist -Xmx ein hartes Limit?

8

Diese SO-Antwort erläutert einige Dinge zum -Xmx JVM-Flag. Versuche zu experimentieren habe ich folgendermaßen gemacht:

%Vor%

Kompiliere es mit javac FooMain.java . Wenn ich es mit einer maximalen Heap-Größe von 5 Millionen Bytes ausführe, bekomme ich:

%Vor%

Obwohl die Zahlen nah genug sind, scheinen sie nicht sehr genau zu sein (mit Ausnahme von total memory am Ende, das genau max memory erreicht). Insbesondere 5368 Arrays mit je 1000 Byte sollten mehr als 5000000 oder sogar 5242880 Byte benötigen. Wie sollen diese Zahlen verstanden werden?

Dies ist das Java, das ich verwende:

%Vor%     
Marcus Junius Brutus 16.10.2015, 07:20
quelle

3 Antworten

5
  

ist -Xmx eine harte Grenze?

Es kommt darauf an, was du mit "hart" meinst. Wenn du meinst "Kann nicht vom Programm geändert werden", dann Ja. Wenn Sie "präzise" meinen, dann Nein. Die Größe der verschiedenen Räume, die der Garbage Collector verwendet, ist ein Vielfaches einer Potenz von 2 Bytes. Und anscheinend rollt die JVM eher nach oben als nach unten.

  

Beispielprogramm, das 1000-Byte-Arrays zuordnet

     

Wie sollen diese Zahlen verstanden werden?

Ein 1000-Byte-Java-Array belegt nicht genau 1000 Bytes:

  • Es gibt eine Objektkopfzeile, einschließlich Platz für ein 32-Bit-Feld length . (In der Regel 3 x 32 Bit).

  • Heap-Knoten werden in Vielfachen von 2 ^ N Bytes zugewiesen. (In der Regel 2 ^ 3 == 8)

Dann hast du die Frage, was die OutOfMemoryError verursacht. Sie könnten denken, dass dies daran liegt, dass der Heap vollständig voll ist. In diesem Fall lautet die Meldung jedoch "GC Overhead Limit überschritten". Das bedeutet, dass die JVM festgestellt hat, dass die JVM einen zu großen Prozentsatz der gesamten CPU-Zeit aufwendet, die den Garbage Collector ausführt. Das hat den GC getötet ... nicht genug Speicher.

Der Grund für das "GC-Overhead-Limit" ist, dass wenn ein Heap voll wird, der GC häufig läuft und immer weniger Speicher beansprucht. Wenn Sie in eine GC "Todesspirale" geraten, ist es besser, den Stopfen schnell zu ziehen, anstatt der Anwendung zu erlauben, bis zum endgültigen Punkt des Versagens zu schleifen.

Wie auch immer ... das bedeutet, dass Ihre Heuristik, um herauszufinden, wie viel Speicher zugeordnet wird, wenn der Heap voll ist, wahrscheinlich falsch ist.

    
Stephen C 16.10.2015, 09:47
quelle
6

Wenn Sie sich den OpenJDK-Quellcode ansehen, ist die Logik zum Ermitteln der maximalen Heap-Größe ziemlich komplex und wird von vielen Variablen bestimmt. Die tatsächliche Größe des Heapspeichers wird in hotspot/src/share/vm/memory/collectorPolicy.cpp festgelegt, verwendet den angegebenen -Xmx-Wert als Eingabe und richtet ihn unter Verwendung des folgenden Codes aus:

%Vor%

align_size_up ist definiert als:

%Vor%

Und max_alignment ist das Produkt der Seitengröße des virtuellen Speichers und der Größe der JVM-Speicherbereinigungskarte. Die VM-Seitengröße beträgt 4096 Byte und die Kartengröße beträgt 512 Byte. Wenn Sie diese Werte einstecken, erhalten Sie eine tatsächliche MaxHeapSize von 6324224 Byte, die gut mit den Zahlen übereinstimmt, die Sie sehen.

Hinweis: Ich habe nur kurz in den JVM-Code geschaut, daher ist es möglich, dass ich etwas übersehen habe, aber die Antwort scheint sich mit dem zusammenzufassen, was Sie sehen.

    
Petter 16.10.2015 09:02
quelle
1

Ihre Frage wird inzwischen von anderen Leuten so ziemlich beantwortet, aber aus Interesse habe ich die Mathematik gemacht: -)

Es heißt hier :

  

Dieser Wert muss ein Vielfaches von 1024 größer als 2 MB sein.

5000000 ist kein Vielfaches von 1024. Meine Schätzung war, dass das Argument auf ein Vielfaches von 1024 aufgerundet wird, was die anderen Antworten bestätigen. Ihr gesamter Speicher (der mehr als nur der angegebene Heap-Speicherbereich ist) ist 5767168, also 5632 * 1024 . Es wurde während der Laufzeit von der ursprünglichen 5242880 auf den wachsenden Heap-Speicherplatz erweitert. Beachten Sie, dass -Xmx das Maximum deklariert, sodass es nicht unbedingt sofort zugewiesen wird. Mit Hilfe von dieser Quelle können wir Ihre Speicherbelegung ermitteln (unter der Annahme von 64bit):

  • 4878000 Bytes für die Bytes
  • 4878 * 24 = 117072 bytes Array-Aufwand
  • einige Bytes für die anderen erstellten Objekte und die Strings
  • eine kleine Speicherschwankung wegen der Speicherbereinigung (zumindest die Zeichenfolge, die Sie bei jeder Iteration erstellt haben, könnte weggeworfen werden)

Also nehmen die Arrays 4995072 Bytes auf, was (zufälligerweise?) schon ein Vielfaches von 1024 wäre. Aber es gibt immer noch den Overhead für die anderen Objekte. Der Heap-Speicherplatz ist also ein Vielfaches von 1024 größer als 4995072 und kleiner 5767168. Wenn wir den freien Platz am Ende betrachten, bleiben 228808 Byte für den Rest der Heap- und Nicht-Heap-Speicherbelegung, was wie eine plausible Zahl klingt.

Endlich ein Wort zum freien Platz am Ende. Die JVM füllt nicht notwendigerweise den gesamten Speicher auf, bevor sie abstürzt. Wenn der Arbeitsspeicher knapp wird, wird die Garbage Collection häufiger ausgeführt. Wenn dies einen bestimmten Prozentsatz der Gesamtlaufzeit beansprucht, endet die JVM , was in deinem Fall passiert ist.

    
André Stannek 16.10.2015 11:10
quelle

Tags und Links