GC -> Allokation in Schleifen

Status
Nicht offen für weitere Antworten.

Zender

Mitglied
Hallo Leute,

mich würde mal interessieren wie der Garbage Collector sich in Schleifen verhält:

Code:
for (int i=0; i<10000; i++)
{
    Integer foo = i*2;
    doSomething(foo);
}

In diesem Beispiel wird die Variable foo ja im Prinzip in jedem neuen Schleifendurchgang neu intialisiert.
Hier hingegn:

Code:
Integer foo;
for (int i=0; i<10000; i++)
{
    foo = i*2;
    doSomething(foo);
}

wird nur einmal die Variable definiert und dann nur neu gesetzt. Macht das einen Unterschied für den GC, oder optimiert der Compiler das eh weg?
Wann genau wird der Speicherplatz von "foo" im ersten Beispielen frei? Erst wenn der GC sich einschaltet, oder wird in beiden Beispielen kein neuer Speicherplatz angefordert, sondern der alte Wert von "foo" vergessen?

Danke für eure Hinweise,
Zender
 
S

SlaterB

Gast
man darf Programmcode nicht so wörtlich nehmen,

innerhalb einer Schleife wird eh nix allokiert, wenn ich mich recht erinnere,
die Variable braucht 4 Byte und die wird wie alle lokalen Variablen sowie sonstige Informationen der Methode
(wie Rücksprung zum Aufrufer) zu Beginn der Methode einmalig reserviert (auf dem Stack-Speicher)

kann sein dass ich das jetzt auch falsch erinnere oder gar eine falsche Sicht habe,
aber solange du nicht was von Assembler-Code gehört hast,
kannst du wohl keine Annahmen über Speicherbedarf machen

-----

eine andere Frage ist neben den 4 Bytes für die Variable noch die vielleicht 50 Bytes für das Integer-Objekt im Heap,
das ist nun gänzlich unabhängig von lokalen Variablen


edit:
vielleicht bezieht sich deine Frage auch nur auf den Heap, klingt beim zweiten Lesen schon etwas intelligenter als beim ersten ;)
 

Marco13

Top Contributor
Zu klären wäre vielleicht noch, ob es eine rein akademische Frage ist, oder irgendeinen praxisbezug hat. Man könnte je nach Fall die eine oder andere flapsige Antwort geben:
"Schau dir den generierten bytecode an"
"Programmierst du einen Microcontroller, oder warum kommt's auf 28 byte an?"
...
Die universalantwort für alle praktischen Anwendungen ist: Schreib's so, dass es übersichtlich und verständlich ist. Die Fausregel ist, dass man den scope (Gültigkeitsbereich) von Variablen so klein wie möglich halten sollte. Wenn man dort ein Performanceproblem vermutet, sollte man dem Just-In-Time-Compiler eine Chance geben, und einen Profiler drüberlaufen lassen....
 

Zender

Mitglied
jap, ich bezog mich nur auf den Heap, hätte ich dazu schreiben sollen ;)

Ich hab mir eher die Frage gestellt, ob eben dem Integer-Objekt, wenn ich es in der Schleife neu erstelle, ein anderer Platz auf dem Heap zugewiesen wird, als beim ersten Durchlauf -> Ob der GC das alte Objekt garnicht "löschen" muss, da es bereits neu belegt ist.
 

byte

Top Contributor
Eine Antwort liefert hier nur der erzeugte Bytecode. Die gleiche Frage wurde hier schon mal gestellt. Da hat auch wer den Bytecode gepostet. Vielleicht findest Du den Thread ja noch, wenn Du danach suchst.
 

FArt

Top Contributor
Auch der Bytecode liefert keine Antwort. Die VM optimiert viel zu viel im Laufzeitcompiler (z.B. Reordering, Inlining, ...).

Objekte werden erst in der Young Generation angelegt. Nur wenn dort kein Platz ist, oder wenn sie länger dort verbleiben altern sie und wandern in den Heap.
Erstere können (und werden) schnell collected, im Heap wird es etwas aufwendiger. Hier ist wenn ich mich recht erinnere ein full gc nötig.

Wenn man den Scope also so klein wie möglich hält gibt man der VM die Möglichkeit sich zur Laufzeit optimal zu verhalten.
 

Zender

Mitglied
Hm, die Ausgangssituation, die zu dieser Frage führt war eigentlich folgende:
Ich durchlaufe in meinem Programm sehr oft die gleiche Schleife, in der relativ mehrere Objekte mit großem Speicherverbrauch geladen werden. Im nächsten Durchlauf werden diese Objekte dann entsprechend neu belegt.
Was mich nun verwundert, ist die Tatsache, dass der Speicherbrauch mit jedem Schleifendurchlauf konstant ansteigt, bis schließlich eine OutOfMemoryError-Exception fliegt.

Da ich nicht so vertraut mit Java bin, wollte ich daher wissen, ob es da beim GC spezielle Sachen zu beachten gibt.

Wie sollte man allgemein bspw mit ByteStreams umgehen? Müssen diese geschlossen werden, oder reicht es, wenn im nächsten Durchlauf die Variable anders intialisiert wird?
 
M

maki

Gast
>> bis schließlich eine OutOfMemoryError-Exception fliegt.

Welche genau?
 
M

maki

Gast
Interessant, hatte ich so noch nie.

Der Link erklärt sehr gut das Problem: Der GC läuft ständig, Speicher wird allerdings nicht wirklich frei, du brauchst einfach mehr Speicher als da ist.

Schliesse die Streams und setze die Referenz auf null, imho.
Zum testen zumindest, die Standard Speichereinstellungen reichen ime nie, aber man sollte es dem GC so einfach wie möglich machen, ansonsten -> mehr Heap
 

Zender

Mitglied
maki hat gesagt.:
Interessant, hatte ich so noch nie.

Der Link erklärt sehr gut das Problem: Der GC läuft ständig, Speicher wird allerdings nicht wirklich frei, du brauchst einfach mehr Speicher als da ist.

Schliesse die Streams und setze die Referenz auf null, imho.
Zum testen zumindest, die Standard Speichereinstellungen reichen ime nie, aber man sollte es dem GC so einfach wie möglich machen, ansonsten -> mehr Heap

Ich habe ihm schon weit mehr als genug Heap zugiesen. Das Problem ist, dass in den ersten Schleifendurchläufen ja auch absolut genug Speicher zur Verfügung steht (stets mehr als 500MB frei, der maximale Heap (Xmx) ist auf 1500MB gesetzt. Nur scheint er dann immer mehr Speicher zu "verlieren", sodass nach 20 Durchläufen auf einmal die Exception fliegt.

Die Streams waren nur ein Beispiel, ich verwende ebenso MySQL und Apache Lucene. Kann man denn allgemein sagen, dass bestimmte Objekte einfach geschlossen werden müssen, damit der Speicher frei wird, auch wenn sie in der Zwischenzeit (neuer Schleifendurchlauf) bereits wieder verwendet werden?
Gibts spezielle Sachen, die einfach immer freigegeben werden sollten?

Vielen Dank für eure Hilfe, Zender
 
M

maki

Gast
Generell gesagt sollte man alles scliessen was man mal geöffnet hat.

der maximale Heap (Xmx) ist auf 1500MB gesetzt
Hört sich nach einem Windows System an, unter Linux geht etwas mehr Heap.

. Nur scheint er dann immer mehr Speicher zu "verlieren", sodass nach 20 Durchläufen auf einmal die Exception fliegt.
Würde mal das GC logging einschalten um genau zu sehen wo das Problem ist, man könnte zB auch die NewGen oder PernGen erhöhen.
 
G

Guest

Gast
Ark hat gesagt.:
Irgendwie habe ich den Code selbst in Verdacht ...

Was genau meinst du mit den Code selbst? Mir ist klar, dass ich irgendwo einen Fehler mache, nur hab ich nicht die Java-Erfahrung um zu wissen, wie man Memory Leaks vermeidet bzw aufspürt.
Wo kann man Fehler machen, wenn im Prinzip alle Objekte immer wieder neu initialisiert werden?

Es ist btw ein Linux System, aber auch bei dem ist der maximale Heap durch den RAM begrenzt? (Ich kann nicht den gesamten RAM nutzen.)
 

Ark

Top Contributor
Anonymous hat gesagt.:
Was genau meinst du mit den Code selbst? Mir ist klar, dass ich irgendwo einen Fehler mache, nur hab ich nicht die Java-Erfahrung um zu wissen, wie man Memory Leaks vermeidet bzw aufspürt.
Wo kann man Fehler machen, wenn im Prinzip alle Objekte immer wieder neu initialisiert werden?
Na ja, z.B. invariante Objekte in Schleifen neu anlegen, Operationen auf Strings (was ja nicht wirklich geht, denn Strings sind ja unveränderlich!) ...

Ark
 
M

maki

Gast
Memory Leaks kann man zB. mit Profilern aufspüren.

Es ist btw ein Linux System, aber auch bei dem ist der maximale Heap durch den RAM begrenzt? (Ich kann nicht den gesamten RAM nutzen.)
Achso, dachte du hättest mind. 2 GiB, denn selbst dann wären 1,5GiB das Limit unter Windows.

Wann zeigst du uns endlich deinen Code?! ;)
 

didjitalist

Bekanntes Mitglied
gibt ne faustformel: je kleiner der scope einer variable, desto höher die wahrscheinlichkeit, dass der GC sie sehr effizient auch wieder abräumen kann.

ein häufig anzutreffender "fehler" sind collections als felder, die für temporäre objekte verwendet werden. das ist grundsätzlich gar nicht so doof, wenn irgendeine methode sehr oft gerufen wird und man sich die realllozierung von speicher sparen möchte. aber oft werden solche collections mit tonnen an die daten gefüllt, die danach nie wieder gebraucht werden, die enthaltende klasse wird aber wiederrum als feld in irgendeiner langlebigen klasse gehalten. und schon ballern diese objekte den speicher länger voll, als nötig gewesen wäre.

oder auch anders gesagt, sind lokale defintionen überhaupt nicht schlimm. und selbst ein lokales new ist nicht dramatisch. in java ist "new" bei weitem nicht so "böse", wie in sprachen wie c++.
 

Zender

Mitglied
Ark hat gesagt.:
Anonymous hat gesagt.:
Was genau meinst du mit den Code selbst? Mir ist klar, dass ich irgendwo einen Fehler mache, nur hab ich nicht die Java-Erfahrung um zu wissen, wie man Memory Leaks vermeidet bzw aufspürt.
Wo kann man Fehler machen, wenn im Prinzip alle Objekte immer wieder neu initialisiert werden?
Na ja, z.B. invariante Objekte in Schleifen neu anlegen, Operationen auf Strings (was ja nicht wirklich geht, denn Strings sind ja unveränderlich!) ...

Ark

Hi Ark,

könntest du das bitte noch etwas erläutern?
Meinst du mit "invariante" Objekte neu anlegen, dass ich in versch. Schleifendurchgängen die Objekte mit den gleichen Werten neu initialiere, sprich gleich den alten Wert belassen könnte?

Mir ist auch nicht klar, was du mit "Operationen auf Strings" meinst. Ich führe sehr viele String-Operationen durch. Viele toLowerCase, compares aber auch Regex-Operationen (direkt mit String.replaceAll, Matches)... etc

Beispielsweise:
Code:
String search = GetPattern(i);
Matcher match = Pattern.compile(search).matcher(stringToMatch);
if (match.find())
{
// ... logik
}

Diese Stellen treten millionenfach während der Ausführung auf. Ich gebe dort keinen Speicher oder ähnliches frei, müsste ich diesbezüglich noch irgendetwas explizit aufrufen?

Vielen Dank für eure umfassende Hilfe,
Zender[/code]
 

Ark

Top Contributor
Na ja, aus einem so kleinen Codeschnipsel lässt sich nun nicht sehr viel ablesen. ;)

Zeig doch einfach mal die wichtigsten (geschachtelten) Schleifen, die dein Programm ausmachen.

Ark
 
G

Guest

Gast
Ark hat gesagt.:
Na ja, aus einem so kleinen Codeschnipsel lässt sich nun nicht sehr viel ablesen. ;)

Zeig doch einfach mal die wichtigsten (geschachtelten) Schleifen, die dein Programm ausmachen.

Ark

der ist leider sehr weit verteilt, daher nicht machbar.
Ich würde nur gerne wissen, welche potentiellen Fallstricke da lauern. Bzw was du genauer mit deinen Äußerungen bzgl der Strings und invarianten Objekte meintest ;)

Gruß, Zender
 

Ark

Top Contributor
Redundanzen erkennt man leider auch nur im größeren Zusammenhang/Überblick. ;)

Invarianten sind wie konstante Faktoren: Man kann sie immer rausziehen. ;) Wenn ein (Funktions-)Wert nur von Konstanten abhängt, dann ist auch dieser Wert konstant. Aber das ist allgemeines Blabla. Ohne Code kann man leider nicht mehr viel machen. Gibt es denn vielleicht so etwas wie eine zentrale Stelle im Code? Die könnte man ja als Erstes unter die Lupe nehmen.

Ark
 
G

Guest

Gast
Ark hat gesagt.:
Redundanzen erkennt man leider auch nur im größeren Zusammenhang/Überblick. ;)

Invarianten sind wie konstante Faktoren: Man kann sie immer rausziehen. ;) Wenn ein (Funktions-)Wert nur von Konstanten abhängt, dann ist auch dieser Wert konstant. Aber das ist allgemeines Blabla. Ohne Code kann man leider nicht mehr viel machen. Gibt es denn vielleicht so etwas wie eine zentrale Stelle im Code? Die könnte man ja als Erstes unter die Lupe nehmen.

Ark

Hm, mit Code kann ich leider nicht wirklich dienen. Ich werde den morgen nochmal genau unter die Lupe nehmen, nur weiß ich nicht wirklich wonach ich suchen soll. Soweit ich weiß passiert nichts ala "Ich füge ein Objekt einer Liste hinzu bevor ich es lösche, oder refererenziere es sonstwie". Im Prinzip wird jedes Objekt immer wieder neu initialisert, daher sollte doch der Speicher des alten (vorher in dieser Variablen gespeicherten) Objektes sofort freigegeben werden.

Ich würde ja gerne einen Profiler drüberlaufen lassen, aber ich vermute stark, dass der Output so immens groß ist, dass dieser nicht analysierbar ist. Ich lasse immerhin pro Schleifendurchgang (halbe Minute Laufzeit) mehrere hundert Tausend Strings analyiseren, und in Lucene/MySQL teilweise abspeichern...

Trotzdem danke für deine Bemühungen. Gruß, Zender
 

didjitalist

Bekanntes Mitglied
Anonymous hat gesagt.:
Im Prinzip wird jedes Objekt immer wieder neu initialisert, daher sollte doch der Speicher des alten (vorher in dieser Variablen gespeicherten) Objektes sofort freigegeben werden.

nicht zwangsläufig. wenn man _richtig_ viele kleine objekte in sehr kurzer zeit erzeugt, kann es schonmal passieren, dass dem GC keine resourcen eingeräumt werden und der heap tatsächlich vollrennt. wenn man vor solchen problemen steht, kann es durchaus sinnvoll sein, an geeigneter stelle der vm bescheid zu sagen, dass jetzt ein guter zeitpunkt zum aufräumen sein könnte.
 

Zender

Mitglied
didjitalist hat gesagt.:
Anonymous hat gesagt.:
Im Prinzip wird jedes Objekt immer wieder neu initialisert, daher sollte doch der Speicher des alten (vorher in dieser Variablen gespeicherten) Objektes sofort freigegeben werden.

nicht zwangsläufig. wenn man _richtig_ viele kleine objekte in sehr kurzer zeit erzeugt, kann es schonmal passieren, dass dem GC keine resourcen eingeräumt werden und der heap tatsächlich vollrennt. wenn man vor solchen problemen steht, kann es durchaus sinnvoll sein, an geeigneter stelle der vm bescheid zu sagen, dass jetzt ein guter zeitpunkt zum aufräumen sein könnte.

ok, aber daran scheint es nicht zu liegen. Ich hab der VM am ANFANG jeder Schleife einfach mal per System.gc() die Möglichkeit gegeben, aufzuräumen. Aber das Problem mit dem Vollaufen des Speichers hab ich immer noch.
Ich bin mir sicher, dass in keinem Schleifendurchgang soviel allokiert wird, dass allein dies dazu führen würde, dass der Heap überquillt. Alles etwas verwunderlich...

Hat noch jemand ein paar Infos bzgl. der String-Sache für mich?

Viele Grüße,
Zender
 

Ark

Top Contributor
Ohne Code kann man nicht mehr viel machen. ;)

Du kannst dich zwar noch mal allgemein darüber informieren, wann man Strings meiden sollte (und welche Alternativen es gibt, und wann man sie einsetzen sollte und wann nicht), aber wirklich helfen kann man dir nicht, wenn du nicht endlich etwas mehr Code rausrückst.

Ark
 

FArt

Top Contributor
Zender hat gesagt.:
Ich hab der VM am ANFANG jeder Schleife einfach mal per System.gc() die Möglichkeit gegeben, aufzuräumen.
Ich glaube hier im Forum kann man sich manchmal sinnlos die Finger wund schreiben. Noch mal für die Lansamen: ein System.gc() wird die nie vor einem OutOf Memory bewahren. Das macht die VM selbständig, wenn sie Speicher benötigt.

Der Speicher läuft voll, wenn so viele Objekte referenziert werden wie in den Speicher passen und danach ist Schluß.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
F KI / Machine Learning Parameter verschachtelte for Schleifen Allgemeine Java-Themen 2
F KI / Machine Learning Parameter verschachtelte for Schleifen Allgemeine Java-Themen 1
A Mehrere for-Schleifen Allgemeine Java-Themen 2
Monokuma Foreach Schleifen in Streams umändern Allgemeine Java-Themen 23
Junger_Basileus Attribute, Arrays, Schleifen Allgemeine Java-Themen 9
E Angabe wie groß Array sein soll und in for-schleifen diesen Array füllen Allgemeine Java-Themen 3
D Integer-Array variabler Größe mit Zahlen befüllen (Schleifen) Allgemeine Java-Themen 0
C Schachbrett mit while-schleifen Allgemeine Java-Themen 7
P Erste Schritte Dynamische Anzahl von verschachtelten Schleifen Allgemeine Java-Themen 5
R kann man irgendwie mit Arrays mit Eingabefenstern und Schleifen Werte abklappern? Allgemeine Java-Themen 2
R n verschachtelte Schleifen? Allgemeine Java-Themen 14
S Welcher Schleifen type für eine Berechnung Allgemeine Java-Themen 7
R Schleifen Allgemeine Java-Themen 11
L for-Schleifen Zählfehler Allgemeine Java-Themen 6
G Code nach Schleifen und Verzweigungen durchsuchen Allgemeine Java-Themen 6
S verzweigungen und schleifen Allgemeine Java-Themen 24
B BigDecimal Schleifen Allgemeine Java-Themen 9
prakdi Zeit zum Durchlauf der Schleifen unverständlich!? Allgemeine Java-Themen 3
B Auslagerung von verschachtelten Schleifen Allgemeine Java-Themen 11
T Verschachtelte Schleifen abbrechen Allgemeine Java-Themen 3
Meldanor For-Schleifen - byte statt int? Allgemeine Java-Themen 11
S Verschachtelte Schleifen Allgemeine Java-Themen 9
A Fibonacci-Zahlen & kopfgesteuerte Schleifen & Strukt Allgemeine Java-Themen 8
V Vererbung und Schleifen Allgemeine Java-Themen 5
W kompliziertes Konstrukt von Schleifen/If/else. Rekursion? Allgemeine Java-Themen 22
S schleifen Allgemeine Java-Themen 3
A Schleifen in Ant? Allgemeine Java-Themen 5
G Methode mit Schleifen NullPointerException Allgemeine Java-Themen 2
L Schleife über Schleifen Allgemeine Java-Themen 4
M Verschachtelte Schleifen (unbekannte Tiefe) Allgemeine Java-Themen 3
N Code verkürzen(mit schleifen)? Allgemeine Java-Themen 10
C Effektivitaet bei for Schleifen Allgemeine Java-Themen 18
C Performance von FOR Schleifen Allgemeine Java-Themen 25
R Lohnt sich byte und short bei Schleifen? Allgemeine Java-Themen 9
P Schleifen liefern Werte nicht wie erwartet Allgemeine Java-Themen 2

Ähnliche Java Themen

Neue Themen


Oben