Überlegen Sie, was einen Java-Prozess ausmacht.
Sie haben:
- die JVM (ein C-Programm)
- JNI Daten
- Java Bytecode
- Java Daten
Bemerkenswert ist, sie alle leben in der C Heap (der JVM-Heap ist natürlich ein Teil des C-Heaps).
Im Java-Heap sind einfach Java-Byte-Codes und die Java-Daten. Was aber auch im Java-Heap ist, ist "freier Speicherplatz".
Die typische (d. H. Sun) JVM wächst nur Java Heap wie nötig, verkleinert sie aber nie. Sobald es sein definiertes Maximum erreicht (-Xmx512M), hört es auf zu wachsen und behandelt alles, was noch übrig ist. Wenn dieser maximale Heap erschöpft ist, erhalten Sie die OutOfMemory-Ausnahme.
Was diese Xmx512M Option NICHT tut, ist die Gesamtgröße des Prozesses zu begrenzen. Es beschränkt nur den Java-Heap-Teil des Prozesses.
Zum Beispiel könnten Sie ein künstliches Java-Programm haben, das 10 MB Java Heap verwendet, aber einen JNI-Aufruf aufruft, der 500 MB C Heap zuweist. Sie können sehen, wie groß die Prozessgröße ist, obwohl der Java-Heap klein ist. Mit den neuen NIO-Bibliotheken können Sie auch Speicher außerhalb des Heapspeichers anhängen.
Der andere Aspekt, den Sie berücksichtigen müssen, ist, dass der Java GC normalerweise ein "Copying Collector" ist. Das bedeutet, dass es die "Live" -Daten aus dem Speicher, den es sammelt, benötigt, und es in einen anderen Speicherabschnitt kopiert. Dieser leere Platz, der kopiert wird, ist NICHT TEIL DES HEAPS, zumindest nicht in Bezug auf den Xmx-Parameter. Es ist wie "der neue Heap" und wird nach der Kopie Teil des Heaps (der alte Space wird für den nächsten GC verwendet). Wenn Sie über einen 512-MB-Heapspeicher mit 510 MB verfügen, kopiert Java die Live-Daten an einen anderen Speicherort. Der naive Gedanke wäre zu einem anderen großen offenen Raum (wie 500 + MB). Wenn alle Ihre Daten "live" wären, dann würde es einen großen Brocken wie diesen brauchen, um hineinkopieren zu können.
So können Sie sehen, dass Sie in den extremsten Rand Fällen mindestens doppelt so viel freien Speicher auf Ihrem System benötigen, um eine bestimmte Heap-Größe zu behandeln. Mindestens 1 GB für einen 512 MB großen Heap.
Es stellt sich heraus, dass nicht der Fall in der Praxis und Speicherzuordnung und solche ist komplizierter als das, aber Sie benötigen einen großen Teil des freien Speichers, um die Heap-Kopien zu behandeln, und dies wirkt sich auf die Gesamtprozessgröße.
Schließlich ist zu beachten, dass die JVM Dinge wie mapping in den rt.jar-Klassen in der VM Spaß macht, um den Start zu erleichtern. Sie sind in einem schreibgeschützten Block zugeordnet und können für andere Java-Prozesse freigegeben werden. Diese geteilten Seiten werden gegen alle Java-Prozesse "gezählt", obwohl sie wirklich nur einmal physischen Speicher verbrauchen (die Magie des virtuellen Speichers).
Nun, warum Ihr Prozess weiter wächst, wenn Sie niemals die Java OOM-Nachricht treffen, bedeutet dies, dass Ihr Leck NICHT im Java-Heap ist, aber das bedeutet nicht, dass es sich nicht in etwas anderem befindet JRE-Laufzeit, eine JNI-Bibliothek von Drittanbietern, ein nativer JDBC-Treiber usw.).