50 Stimmen

Java verweigert den Start - Konnte nicht genügend Platz für den Objekt-Heap reservieren

Hintergrund

Wir haben einen Pool von etwa 20 Linux-Blades. Auf einigen läuft Suse, auf einigen Redhat. Alle teilen sich einen NAS-Speicherplatz, der die folgenden 3 Ordner enthält:

  • /NAS/app/java - ein Symlink, der auf eine Installation eines Java JDK verweist. Derzeit Version 1.5.0_10
  • /NAS/app/lib - ein Symlink, der auf eine Version unserer Anwendung verweist.
  • /NAS/data - Verzeichnis, in das unsere Ausgabe geschrieben wird

Alle unsere Rechner haben 2 Prozessoren (Hyperthreading) mit 4 GB physischem Speicher und 4 GB Swap-Speicher. Wir begrenzen die Anzahl der "Aufträge", die jeder Rechner gleichzeitig verarbeiten kann, auf 6 (diese Zahl muss wahrscheinlich geändert werden, aber das spielt bei dem aktuellen Problem keine Rolle, also ignorieren Sie es bitte vorerst).

Einige unserer Aufträge legen eine maximale Heap-Größe von 512 MB fest, andere wiederum reservieren eine maximale Heap-Größe von 2048 MB. Auch hier ist uns klar, dass der verfügbare Arbeitsspeicher überschritten werden könnte, wenn 6 Aufträge auf demselben Rechner mit einer Heap-Größe von 2048 gestartet würden, aber das ist unseres Wissens noch nicht vorgekommen.

Das Problem

Es kommt vor, dass ein Auftrag sofort mit der folgenden Meldung fehlschlägt:

Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.

Früher haben wir das auf zu viele gleichzeitig laufende Aufträge auf demselben Rechner geschoben. Das Problem trat selten genug auf ( MAYBE einmal im Monat), dass wir es einfach neu starten würden und alles in Ordnung wäre.

Das Problem hat sich in letzter Zeit noch verschlimmert. Alle unsere Aufträge, die eine maximale Heap-Größe von 2048m anfordern, schlagen fast jedes Mal sofort fehl und müssen mehrmals neu gestartet werden, bevor sie abgeschlossen werden können.

Wir sind zu den einzelnen Rechnern gegangen und haben versucht, sie manuell auszuführen - mit demselben Ergebnis.

Fehlersuche

Es stellte sich heraus, dass das Problem nur bei unseren SuSE-Boxen besteht. Der Grund dafür, dass es häufiger auftritt, ist, dass wir mehr Rechner hinzugefügt haben, und die neuen sind SuSE.

cat /proc/version' auf den SuSE-Boxen liefert uns:

Linux version 2.6.5-7.244-bigsmp (geeko@buildhost) (gcc version 3.3.3 (SuSE Linux)) #1 SMP Mon Dec 12 18:32:25 UTC 2005

cat /proc/version' auf den RedHat-Rechnern liefert uns:

Linux version 2.4.21-32.0.1.ELsmp (bhcompile@bugs.build.redhat.com) (gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-52)) #1 SMP Tue May 17 17:52:23 EDT 2005

uname -a' gibt uns auf BEIDEN Rechnertypen folgendes an:

UTC 2005 i686 i686 i386 GNU/Linux

Auf dem Rechner laufen keine Aufträge, und keine anderen Prozesse belegen viel Speicher. Alle derzeit laufenden Prozesse könnte insgesamt 100 MB verbrauchen.

top" zeigt derzeit Folgendes:

Mem:   4146528k total,  3536360k used,   610168k free,   132136k buffers
Swap:  4194288k total,        0k used,  4194288k free,  3283908k cached

vmstat' zeigt derzeit Folgendes an:

procs -----------memory---------- ---swap-- -----io---- --system-- ----cpu----
r  b   swpd   free   buff  cache   si   so    bi    bo   in    cs us sy id wa
0  0      0 610292 132136 3283908    0    0     0     2   26    15  0  0 100  0

Wenn wir einen Auftrag mit der folgenden Befehlszeile starten (maximaler Heap von 1850 MB), startet er problemlos:

java/bin/java -Xmx1850M -cp helloworld.jar HelloWorld
Hello World

Wenn wir die maximale Heap-Größe auf 1875 MB erhöhen, schlägt es fehl:

java/bin/java -Xmx1875M -cp helloworld.jar HelloWorld
Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.

Es ist ziemlich klar, dass der derzeit verwendete Speicher für die Zwischenspeicherung verwendet wird und deshalb so wenig als "frei" angezeigt wird. Was nicht klar ist, ist, warum es eine magische Grenze von 1850 MB gibt, bei der alles, was darüber liegt, bedeutet, dass Java nicht starten kann.

Für Erklärungen wären wir Ihnen sehr dankbar.

21voto

Jon Bright Punkte 13050

Da Sie ein 32-Bit-Betriebssystem verwenden, wird die Gesamtgröße begrenzt sein. In anderen Antworten wurde dies bereits ausführlicher behandelt, so dass ich deren Informationen nicht wiederholen werde.

Ein Verhalten, das ich kürzlich bei unseren Servern festgestellt habe, ist, dass die Angabe einer maximalen Heap-Größe mit -Xmx ohne Angabe einer Mindestgröße des Heaps mit -Xms würde dazu führen, dass die Server-VM von Java sofort versuchen würde, den gesamten für die maximale Heap-Größe benötigten Speicher zuzuweisen. Und wenn die Anwendung diese Heap-Größe erreicht, ist das natürlich die Menge an Speicher, die Sie benötigen. Aber die Chancen stehen gut, dass Ihre Anwendungen mit vergleichsweise kleinen Heaps beginnen und Mai den größeren Heap zu einem späteren Zeitpunkt benötigen. Durch die Angabe der minimalen Heap-Größe können Sie Ihre Anwendung mit einem kleineren Heap beginnen und diesen allmählich vergrößern.

All dies wird Ihnen nicht helfen, Ihre maximale Heap-Größe zu erhöhen, aber ich dachte, es könnte helfen, also...

15voto

Luca Tettamanti Punkte 9526

Wie in anderen Antworten angedeutet, ist das Problem auf die Erschöpfung des virtuellen Adressraums zurückzuführen. Ein 32-Bit-Linux-Benutzerprogramm ist normalerweise auf 3 GB AS begrenzt; das verbleibende 1 GB wird vom Kernel verwendet (Begründung: da die oberen 1 GB vom Kernel fest zugewiesen sind, ist es nicht notwendig, die Seitentabelle zu berühren, wenn Syscalls bedient werden).

RHEL-Kernel implementieren jedoch den so genannten 4GB/4GB-Split, bei dem die vollen 4GB AS für User-Space-Prozesse zur Verfügung stehen, allerdings auf Kosten eines leichten Laufzeit-Overheads (der Kernel lebt in einer separaten 4GB virtuellen AS)

8voto

MarkR Punkte 60862

Die Verwendung eines 32-Bit-Betriebssystems ist ein Fehler; Sie sollten auf jeden Fall so bald wie möglich aufrüsten.

Ich weiß nicht, ob Java seinen Heap in einem einzigen zusammenhängenden Stück benötigt, aber wenn ja, klingt die Forderung nach 1,8 GB Heap auf einem 32-Bit-Rechner nach einer großen Aufgabe. Sie gehen davon aus, dass ein Teil des Adressraums, fast die Hälfte davon, beim Start der JVM frei ist.

Je nachdem, welche anderen Bibliotheken zu diesem Zeitpunkt geladen sind, gibt es möglicherweise keine. Bibliotheken können Speicher an beliebiger Stelle zuweisen, so dass Ihr Adressraum so fragmentiert sein könnte, dass 1,8 GB nicht in einem Stück verfügbar sind.

Unter Linux 32-Bit sind ohnehin nur maximal 3G Adressraum verfügbar. Bibliotheken und die JVM selbst verbrauchen zu Beginn etwas davon.

4voto

Es scheint, dass es für 32-Bit-Server eine JVM-Beschränkung gibt, die nicht überwunden werden kann (es sei denn, Sie finden eine spezielle 32-Bit-JVM, die keine Beschränkung von 2 GB oder weniger auferlegt).

Dieser Thread auf The Server Side enthält weitere Details, einschließlich mehrerer Personen, die verschiedene JVMs auf 32-Bit-Architekturen getestet haben. IBMs JVM scheint 100 MB mehr zu erlauben, aber das bringt nicht wirklich das, was man will.

http://www.theserverside.com/discussions/thread.tss?thread_id=26347

Die "echte" Lösung ist die Verwendung eines 64-Bit-Servers mit einer 64-Bit-JVM, um Heaps von mehr als 2 GB pro Prozess zu erhalten. Es ist jedoch wichtig, auch die Auswirkungen der Erhöhung der Adressgröße (nicht nur des adressierbaren Raums) durch die Verwendung einer 64-Bit-JVM zu berücksichtigen. Bei einer Verarbeitung mit weniger als 4 GB Speicher wird es wahrscheinlich zu Leistungs- und Speichereinbußen kommen.

Ein Denkanstoß: Benötigt jeder dieser Aufträge wirklich 2 GB Speicher? Gibt es eine Möglichkeit, die Aufträge so zu modifizieren, dass sie innerhalb von 1,8 GB laufen, so dass diese Grenze kein Problem darstellt?

3voto

murf Punkte 31

Ich habe zwei Bewerbungen geschrieben, eine mittelgroße und eine ziemlich kleine. Ich würde die die mittelgroße Anwendung (unter Linux, Centos), ohne Args (Java-Server), und sie lief einwandfrei. Aber wenn ich dann die kleinere Anwendung mit "java client" startete, meldete sie dass sie nicht genug Speicherplatz reservieren konnte und nicht laufen würde. Ich experimentierte und benutzte -Xms und -Xmx, beide mit 10m, und beide liefen ohne Beanstandung... Stell dir das mal vor!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X