OutOfMemoryError

Von: , Frage gestellt am Mi, 12. Mai 2004

hiho experten!

hab hier eine aufgabe, bei der ich herausfinden soll, wie gross ich einen String (bzw. StringBuffer) machen kann, befor es $subject Fehler gibt.
is ansich kein problem!
bekomme für String 2^25 byte danach -> OutOfMemoryError
für StringBuffer 2^24 byte danach -> OutOfMemoryError

das problem was sich mir stellt, ist die weitere fragestellung:
... und warum?

tjo... kann mich mal wer aufklären, weshalb grad bei 2^25 der Heap zu gross is?
irgend ne besondere zahl die 33.554.432 ?

danke im voraus!
mfg
Geisterkarle

ps: laut aufgabenstellung habe ich den string immer verdoppelt! weiss nich, ob das wichtig is!

6 Antworten zu dieser Frage

  1. Antwort von nach einer Minute 0 hilfreich
    Re: OutOfMemoryError

    oh, hab grad nochmal getestet. fehler meinerseits!
    bei StringBuffer komm ich nu auch auf 2^25 :)

  2. Antwort von nach 29 Minuten 1 hilfreich
    Re: OutOfMemoryError

    bekomme für String 2^25 byte danach -> OutOfMemoryError
    für StringBuffer 2^24 byte danach -> OutOfMemoryError
    Ich wuerde jetzt mal behaupten, dass "max heap size" der VM auf
    32 MB steht. Mit java -X kannst du rausfinden, wie du diese erhoehen
    kannst, falls gewuenscht (siehe -Xms, -Xmx).

    Gruss, Patrick

    http://java.sun.com/docs/books/vmspec/2nd-edition/ht...

  3. Antwort von nach einer Stunde 0 hilfreich
    Re: OutOfMemoryError

    hab hier eine aufgabe, bei der ich herausfinden soll, wie
    gross ich einen String (bzw. StringBuffer) machen kann, befor
    es $subject Fehler gibt.
    is ansich kein problem!
    bekomme für String 2^25 byte danach -> OutOfMemoryError
    für StringBuffer 2^24 byte danach -> OutOfMemoryError

    das problem was sich mir stellt, ist die weitere
    fragestellung:
    ... und warum?

    tjo... kann mich mal wer aufklären, weshalb grad bei 2^25 der
    Heap zu gross is?
    irgend ne besondere zahl die 33.554.432 ?
    Hi
    je nach JRE (VM) wird die Heapsize festgelegt. Meiner Meinung nach bei Sun JDK 64 MB, aber ich kann mich täuschen. Andere ANbieter von VM (HP, IBM auf AIX etc.) implementieren das anders.
    Wir haben hier software, die problemlos mit SUN tat aber mit IBM nicht, da hatten wir dann denselben Fehler.
    Daher, wie mein Vorredner sagte, -Xms oder -Xmx verwenden und alles wird gut.
    Warum das so ist?
    Keine Ahnung.
    Ich nehme an, da es sich um eine Virtual Machine handelt, muss sie die gesamte Hardware emulieren und die hat eben Heaps und Stacks und was weiss ich.
    Und diese müssen mal einen Defaultwert haben
    Kay

  4. Antwort von nach einer Stunde 0 hilfreich
    thx

    danke den antwortern! :)
    mal sehen, was mein prof sagt... bisle schwammig gestellt wohl die frage!
    mfg
    Geisterkarle

  5. Antwort von nach 6 Stunden 2 hilfreich
    Re: OutOfMemoryError

    Hallo Timo,

    die Implementierung von String und StringBuffer ist eine unterschiedliche.
    Strings sind "immutable", d.h. durch hinzufügen von neuen Zeichen zu einem String bekommst Du immer eine neue Instanz. Deine Varable (nennen wird Sie mal s) zeigt somit immer auf eine neue Instanz eines String-Objekts. Der alte String ist aber immer noch im Speicher und wird vom GC entsorgt.
    Wenn jetzt der Speicher knapp wird, so schlägt der GC immer öfter zu und versucht freien Speicher zu finden. Wenn jetzt durch einen new Aufruf (indirekt wird dies bei Hinzufügen von Zeichen zu einem String gemacht) kein freier Speicher mehr gefunden werden kann, dann wirft die VM eben einen OutOfMemoryError, d.h. es kann kein Speicher mehr freigegeben werden, da der "Pool" für Speicher leer ist (du hast ja den ganzen Speicher belegt).
    Das ist so ähnlich, als könntes Du nur so viel Speicher allozieren, wie Du physikalisch in Deinem Rechner hast. Der Speicher ist i.d.R. in der VM nicht virtualisisert.
    Wie schon meine Vorredner gesagt haben, ist dieser "Pool an Speicher" also der Heap von VM-Implementierung zu VM-Implementierung verschieden. Jedoch kann durch Parameter beim Starten der VM diesen Heap größer (oder auch kleiner) machen.

    Bei dem StringBuffer wird i.d.R. keine neue Instanz des StringBuffer-Objekts erzeugt, aber intern ist trotzdem ein Array in dem die Zeichen gespeichert sind. Dieses muß natürlich angepasst werden, wenn das Array voll ist. Nun stell Dir vor, Dein StringBuffer Objekt hält n Zeichen (und das interne Array ist voll). Wenn nun ein Zeichen hinzukommt, so wird ein neues Array mit n+e Zeichen (mit e eine Konstante; siehe StringBuffer Konstruktor) erzeugt und der Inhalt aus dem alten Array in das neue Array kopiert. Du brauchst also Minimum 2n+e Zeichen-Speicher. Wenn Du aber nur m Zeichen-Speicher hast und m < 2n+e ist, hast Du eben obigen OutOfMemoryError.

    BTW. Du sprichts von Byte für den Speicherverbrauch. Strings werden aber in UTF-8 abgelegt und da kann ein Zeichen unter Umständen schon mal 3 Bytes lang sein. Wenn Du Dich aber auf ASCII beschränkst, kannst Du sizeof(char)=sizeof(byte) annehmen (was man aber eigentlich nicht sollt ;-) hab hier eine aufgabe, bei der ich herausfinden soll, wie
    gross ich einen String (bzw. StringBuffer) machen kann, befor
    es $subject Fehler gibt.
    Hier ist das Wörtchen bevor wohl wichtig. Dann versuch doch eine while-Schleife zu machen, in der Du ein String/StringBuffer Objekt immer n=1024 Zeichen hinzufügst. Das Hinzufügen sicherst Du mit einem try catch-Block ab. Im catch Block fängst Du die Exception ab, setzt den Inhalt Deines neuen Strings/StringBuffers auf null, halbierst Zeichenanzahl n, und nimmst für die nächste Runde den alten Wert. Im catch-Block kannst Du noch System.gc() und Thread.yield() aufrufen um den GC explizit aufzurufen. Wichtig ist nur, dass Du keinen Speicher im catch Block allozierst.
    Mit dieser Methode allozierst Du (bis auf ein Epsilon) den kompletten Speicher.

    Wenn Du n immer verdoppelst, dann ist 2^25 die Zahl die fast der Hälfte des zur Verfügung stehenden Speichers entspricht (Argumentation siehe oben mit 2n+e) (das ist aber jetzt aus dem Bauch geschossen, ohne diese Behauptung bewiesen zu haben; außerdem hängt es von der Implementierung von String.concate bzw. StringBuffer ... ab. Soweit ich weiß, gibt es keine effiziente Methode ein Array um n Einträge zu erweitern. Es muß dazu immer ein neues Array mit (altes Array).length+n Einträgen alloziert werden.

    Ich hoffe, daß ich nicht zu langweilig war.

    Gruß,
    Frank

    • Antwort von nach 9 Stunden 1 hilfreich
      Re^2: OutOfMemoryError

      Ich hoffe, daß ich nicht zu langweilig war.
      nein, natürlich nicht!
      wer sich so viel mühe macht, mir das zu erklären lobe ich eher! *

      das >bevor< is übrigens wirklich korrekt (glaub ich zumindest *g*) bei mir, da ich immer in der while-schleife in reihenfolge:
      string(buffer)-verdoppeln.
      anzahl der elemente in byte (lass da einfach nen int mitlaufen) ausgeben lasse
      und DANN den int verdopple. also is der ausgegebene wert der letzte, der es geschafft hat.

      hab übringes meine aufgabe abgeschickt und tatsächlich schon antwort erhalten.
      er wollte eigentlich nur das von dir angesprochene haben.
      also das string nich geändert werden kann und ein neuer angelegt werden muss, während bei stringbuffer kein neuer eintrag gemacht werden muss.

      ok, thema abgeschlossen :D
      thx!

Keine passende Antwort gefunden? Jetzt eigene Frage stellen!