OutOfMemoryError

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!

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

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…

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

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

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 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

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