Java Heap (Memory-Volume) vergrößern – Windows

Bist du schon mal an ein Speicherlimit in Java gestoßen und wurdest mit der Fehlermeldung „java.lang.OutOfMemoryError: Java heap space“ begrüßt? Ärgerlich, nicht wahr! Aber das kann man ändern!

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
OutOfMemoryError: java heap space

Speicher? Wer achtet noch auf Speicher? Davon haben wir doch heutzutage genug! Vorbei sind die Zeiten mit 16MB EdoRAM – wobei es mir kalt den Rücken runter läuft. Heute sind 4 GB Standard, wenn nicht sogar 8 GB. Aber was wenn deiner Programmiersprache relativ egal ist wie viel Speicher du besitzt, weil diese gedeckelt ist?

Genau das ist mir in der letzten Woche passiert. ich wollte ein Array erstellen, welches locker mal so 1000 x 1000 x 1000 Integer-Werte enthalten sollte. Ja ich gebe es zu, ich bin die Sache relativ naiv angegangen, denn das wäre abzusehen gewesen. Daher möchte ich heute zeigen, wie man Java dazu bringt – bei Bedarf – mehr Speicher zu nutzen.

Zwei Varianten um den Java Heap zu vergrößern

  • Heap vergrößern in Eclipse, speziell für eine Klasse
  • Heap vergrößern in dem auszuführenden .JAR-File, per Batchaufruf

Vorab: Der Code

Vorab möchte ich – dass das Beispiel nicht allzu theoretisch wirkt – ein Code-Schnipsel zeigen. Bei diesem wird ein Integer-Array mit drei Dimensionen angelegt, jede mit einer Größe von 1000 Werten. Im Anschluss wird in jede Array-Größe ein Wert von 1 geschrieben.

//größe einer Array-Dimension
int arraySize=1000;
//Dimensions Counter zur Überprüfung
long l=0;
//Array initialisieren
int[][][]a=new int[arraySize][arraySize][arraySize];

//Alle Dimensionen durch gehen
for(int x=0;x<arraySize;x++){
    for(int y=0;y<arraySize;y++){
        for(int z=0;z<arraySize;z++){
            //Dimension mit 1 belegen
            a[x][y][z]=1;
            //counter hochzählen
            l++;
        }
    }
}
//wie viele Dimensionen wurden beschrieben
System.out.println(l);

Verhängnisvolles Kubik

Anfänglich sieht das ganze harmlos aus, doch bei genauer Berechnung stellt sich heraus, dass diese Annahme naiv ist. Ein Integer-Wert ist in Java mit 32 Bit umgrenzt. Das heißt, bei 1000³ (1000 * 1000 * 1000) Werten ergibt das 32*10³ (32.000.000.000) Bit. Das ganze durch 8 (Byte), dann durch 1024 (KByte) und nochmal durch 1024 (MByte) ergibt einen Speicherbedarf von 3.814 MB (3,72 GB). … wenn ich mir das so anschaue ist das mehr als naiv!

ArraySizeArraySize³Speichervolumen in MB
2008.000.00030
512134.217.728512
600216.000.000823
800512.000.0001.953
10001.000.000.0003.814

Dazu gibt es natürlich auch wieder ein Berechnungscode. Die Sourcecode-Dateien sind wie immer im Anhang hinterlegt!

/**
 * Gibt das Speichervolumen in MB zurück
 *
 * @param size(count of values)
 * @return size memoryvolume(in MB)
 */
public long calcIntegerHeap(long size){
    // Bit-size
    long l=32*size;
    System.out.println("b:"+l);
    // Byte-size
    l=l/8;
    System.out.println("B:"+l);
    // KByte-size
    l=l/1024;
    System.out.println("KB:"+l);
    // MB-size
    l=l/1024;
    System.out.println("MB:"+l);
    // count of values
    System.out.println(size+"values");
    // rückgabe in MB
    return l;
}

Begrifflichkeiten: Xms und Xmx

Vorab müssen wir noch kurz zwei Begrifflichkeiten klären. Xms gibt das Standardvolumen an, mit dem Eclipse bzw. ein Java Programm gestartet wird. Dieser Speicher wird für das Javaprogramm reserviert. Xmx gibt das Maximum an, die sogenannte Deckelung.

Java Heap vergrößern in Eclipse

Eclipse Heap vergrößern
Eclipse Heap vergrößern

In Eclipse ist es möglich pro Klasse einen minimalen (Xms) und maximalen (Xmx) Speicherbereich zu definieren. Dazu rufst du den Menüpunkt „Run“>“Run Configurations“ auf. Unter „Java Application“ und der gewünschten Klasse wählst du den Reiter „Arguments“.

Unter „VM arguments“ hast du nun die Möglichkeit, deinem Programm Startparameter mitzugeben. Diese würden eigentlich beim Aufruf der fertigen JAR-Datei mitgegeben (siehe Unten „direkter Aufruf des .JAR-File mit Batchdatei“), jedoch wäre es etwas nervig diese immer wieder zu erstellen und auszuführen. So bringt Eclipse diese Funktion von Haus aus mit.

Trage nun im Feld „VM arguments“ folgende Zeilen ein:

- Xms64m
- Xmx512m

und fertig sind wir. Mit den zwei Zeilen sagen wir Eclipse nun, dass wir mindestens 64MB reserviert haben wollen, aber die Deckelung des Speichers bei 512 MB (0,5 GB) liegt. Das heißt auch, dass unser Array jetzt mit 512 Werten pro Dimension initialisiert werden kann. Ok, vielleicht sollte man ein paar weniger Werte nehmen, denn der Long Counter benötigt auch noch ein paar Speicher Ressourcen. Die Werte können jetzt beliebig auch nach oben angepasst werden. Probiere mal den Xmx Wert von 4000 und führe das Array mit einer jeweiligen Dimensionsgröße von 1000 aus!

Direkter Aufruf des .JAR-File mit Batchdatei

Kommen wir noch zum letzten Punkt. Wenn das Java Programm nun irgendwann fertig ist und wir es ausliefern wollen, ohne Eclipse Umgebung, müssen wir dem Programm ebenfalls mitteilen, dass es die Speicherdeckelung hochfährt. Dazu speicherst du die Datei als ausführbares .JAR-File in einen beliebigen Ordner (bspw. heap512.jar). Leg nun eine Textdatei (run.txt) neben das JAR-File. In diese schreibst du folgende Zeilen:

java -Xmx512M -Xms64M -jar heap512.jar
PAUSE

Damit rufen wir manuell unser Java-Programm auf und geben ihm wieder beide Parameter mit. In der zweiten Zeile geben wir noch ein „PAUSE“-Command mit. Dies bezweckt, dass die Konsole – welche als Ausgabe dient – nicht sofort nach Abarbeitung des Programms verschwindet.

Anschließend benennen wir die Datei noch in „run.bat“ um. Das ist wichtig, da sonst Windows nicht versteht, dass es sich um eine ausführbare Batchdatei handelt. Achte darauf, dass dir bei der Textdatei die Ändung mit angezeigt wird (die zumeist ausgeblendet wird), ansonsten erhälst du nach dem Umbenennen in Wirklichkeit eine „run.bat.txt“ Datei und das File bleibt unausführbar.

Download

Video Tutorial

MrKnowing

Programmierer und Wissensnerd! Kontaktiere mich auf Google+ oder einfach per Mail danny@mrknowing.com

Das könnte dich auch interessieren …

3 Antworten

  1. Tobias sagt:

    Kann es sein, dass zwischen dem Minus und dem Argument in Eclipse kein Leerzeichen sein darf? Ich habe deine Argumente nämlich mal kopiert und bekam eine Exception. Ohne Leerzeichen funktioniert es allerdings.

  1. 1. Juni 2013

    […] richtig liegen. Doch wo eine Verschwendung von Speicher hinführen kann, ist in diesem Artikel, zum Javaheap, gut beschrieben. Auch der Aufwand vom hin- und herkonvertieren darf nicht unterschätzt werden. […]

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert