RAM Problem

Ocean15

Aktives Mitglied
Hallo Leute...

Habe ein kleines Problem mit dem Arbeitsspeicher meines Programms.

Es läuft recht flüssig nur taucht momentan bei einigen Nutzern meines Programms folgender Fehler auf:

Java:
java.lang.OutOfMemoryError: Java heap space
at java.util.PriorityQueue.<init>(Unknown Source)
at angriffe.AngriffsverwaltungDorf.<init>(AngriffsverwaltungDorf.java:20)
at dorf.Dorf.<init>(Dorf.java:32)
at dorf.DorfManager.updateDoerfer(DorfManager.java:119)
at aufgaben.Executer.initDoerfer(Executer.java:123)
at aufgaben.Executer.doAufgabe(Executer.java:57)
at aufgaben.Executer.nextAufgabe(Executer.java:35)
at account.Account.action(Account.java:78)
at account.Accountverwaltung.doActions(Accountverwaltung.java:140)
at engine.ProgrammLoop.aktionen(ProgrammLoop.java:95)
at engine.ProgrammLoop.update(ProgrammLoop.java:77)
at engine.ProgrammLoop.run(ProgrammLoop.java:60)
at java.lang.Thread.run(Unknown Source)

Die dazugehörige Methode (Konstruktor) ist folgende:

Java:
public AngriffsverwaltungDorf(Account account, Dorf dorf) {
		this.account = account;
		this.dorf = dorf;
		CompAngriffe comp = new CompAngriffe();
		eigeneBefehle = new PriorityQueue<Angriff>(1000000,comp);
	}


Der Fehler ist offensichtlich: Zu wenig Arbeitsspeicher den die JRE bereitstellt. Aber wie reagiere ich auf so einen Fehler? Ist es irgendwie möglich meinem Programm mehr Arbeitsspeicher zur Verfügung zu stellen?

Ich habe auch die RAM Werte des Programms bei den Nutzern auslesen lassen. Hier die Werte und wie ich sie bekommen habe:

RAM Total: 259522560
RAM Frei: 3448
RAM Aktuell: 259519208

Java:
String memoryTotal = String.valueOf(rt.totalMemory());
		String memoryFree = String.valueOf(rt.freeMemory());
		String memoryNow = String.valueOf(rt.totalMemory() - rt.freeMemory());

Hoffe auf Hilfe!
Ocean15
 
das problem ist nicht das deine user zuwenig ram haben ... sondern das du ihn zu krass verschwendest

warum erstellst du eine liste mit 1 Mio größe ? werden denn wirklich jemals irgendwann auch nur annährend so viele benötigt ?

DA solltest du erstmal anfangen zu überlegen und zu fixen anstatt gleich das problem bei irgendwelchen usern zu suchen ... den der fehler steckt in deinem code


tipp : lass die größen-angabe weg und lass eher java das ganze verwalten ... dann sollte das problem behoben sein
 
Ja, der Wert ist realistisch. Aber du hast recht, am liebsten wäre es mir wenn ich nichts angebe. Aber bei Übergabe eines Comperators verlangt die Methode auch die Gesamtlänge als Parameter.
 
Hab boch nie mit PriorityQueue gearbeitet. Aber beim kurzen drüberschauen ist mir aufgefallen, dass es in der Klasse eine Methode grow() gibt. Die scheint das queue Array bei bedarf zu vergrössern. Also spräche eigentlich nichts dagegen die initiale Grösse klein zu halten. Oder gleich auf das Minimum "1".

Wie gesagt, ich kenne mich mit PriorityQueue nicht aus. Kann sein, dass es Performance Probleme bereiten kann; kann auch sein, dass es zu irgendwelchen anderen Problemen kommt. Aber einen Versuch wär's doch wert, oder?
 
Bei mir steht im Code von grow, die AUTOMATISCH aufgerufen wird, wenn bei offer die Queue zu "kurz" ist.

Java:
 // Double size if small; else grow by 50%
        int newCapacity = oldCapacity + ((oldCapacity < 64) ?
                                         (oldCapacity + 2) :
                                         (oldCapacity >> 1));

Also starte mit einer VIEL kleineren Anfangsgrösse (und lasse Java seinen Lauf😀)
 
Zuletzt bearbeitet:
Ich könnte mir vorstellen, dass das Performance Vorteile hat.

Wenn die grow() Methode bei jedem hinzufügen eines neuen Elements das Array vergrösserte, würde das ab einer gewissen Grösse sehr viel Zeit in Anspruch nehmen. Darum wird wohl ab zb 65 Elementen das Array gleich um 50% vergrössert. So kannst du ca. weitere 32 Elemente hinzufügen ohne, dass das Array vergrössert werden muss.

Es wird vielleicht klarer, wenn man sieht wie die grow() Methode verwendet wird. Ist übrigens private und wird wie schon gesagt wurde nur bei offer() benutzt.

Aus der PriorityQueue.class der JRE 6u18:
Java:
public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        modCount++;
        int i = size;
        if (i >= queue.length)
            grow(i + 1);
        size = i + 1;
        if (i == 0)
            queue[0] = e;
        else
            siftUp(i, e);
        return true;
    }

private void grow(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
	int oldCapacity = queue.length;
        // Double size if small; else grow by 50%
        int newCapacity = ((oldCapacity < 64)?
                           ((oldCapacity + 1) * 2):
                           ((oldCapacity / 2) * 3));
        if (newCapacity < 0) // overflow
            newCapacity = Integer.MAX_VALUE;
        if (newCapacity < minCapacity)
            newCapacity = minCapacity;
        queue = Arrays.copyOf(queue, newCapacity);
    }
 
Ich habe mal einen kleinen Test gemacht. Hier werden 1000 Objekte "geoffered".
Das Kopieren des Arrays findet in folgenden Schritten statt
Code:
11,24,50,102,153,229,229,343,343,514,771,1156.
 
Ich habe mal einen kleinen Test gemacht. Hier werden 1000 Objekte "geoffered".
Das Kopieren des Arrays findet in folgenden Schritten statt
Code:
11,24,50,102,153,229,229,343,343,514,771,1156.

Dann sollte es gehen wenn ich die Größe 1 übergebe und immer offer da sich die quee dann automatisch vergrößert oder hab ich das falsch verstandnen?
 

Zurück
Oben