JAVA - Ruhezustand berechnen < Softwaretechnik+Pro < Praktische Inform. < Hochschule < Informatik < Vorhilfe
|
Aufgabe | StackOverflowError!!! |
Glück Auf!
Ich habe folgendes Problem:
Bei der Implementierung eines LogikSimulators kann ich den Ruhezustand einer Schaltung nicht berechnen. Der Grund dafuer:
StackOverflowError.
Ich habe zwar herausbekommen, dass dies ein Speicherproblem darstellt, aber wie das zu lösen ist,...?
Googleergebnisse brachten nur, dass das Stack zu klein ist (???)
(An dieser Stelle sollte ich vielleicht auch sagen, dass ich Java-Newbie bin).
Das Problem taucht natuerlich nur bei Rueckkopplungen auf.
Die Berechnung des Ruhezustandes hab ich realisiert, indem ich die betreffenden Gatter bei der Berechnung des Ausganges (verzoegerungsfrei) einfach mitzaehlen lasse und bei einer Zahl aussteigen lasse.
Das funktioniert bei kleinen Schaltungen recht gut, aber bei komplexen Schaltungen geht das nicht mehr.
Ich habe mal getestet, wie oft ich den Ausgang eines einzigen Nor-Gatters
(Input a,b, Output b) berechnen kann: ca. 1000mal
Bei einer etwas groesseren Schaltung mit einigen Rueckkopplungen sind es nur noch 140mal, obwohl ich ca. 5000mal bräuchte.
Ist zwar alles sehr miserabel beschrieben, aber ich hoffe mal, Ihr versteht das Problem.
mfg
Chochalski
|
|
|
|
Status: |
(Antwort) fertig | Datum: | 10:30 Di 15.05.2007 | Autor: | Frank05 |
> Ich habe zwar herausbekommen, dass dies ein Speicherproblem
> darstellt, aber wie das zu lösen ist,...?
> Googleergebnisse brachten nur, dass das Stack zu klein ist
> (???)
> (An dieser Stelle sollte ich vielleicht auch sagen, dass
> ich Java-Newbie bin).
Ich schließe mal aus deiner Beschreibung und der Fehlermeldung, dass deine Implementierung rekursiv ist.
Du solltest dich mal mit Rekursion vertrauter machen. Dein Problem hat nicht mit Java direkt zu tun, sondern damit, dass bei rekursiven Funktionen generell immer ein Problem mit der Stacktiefe auftaucht, weil bei jedem rekursiven Aufruf ein neuer Stackeintrag gemacht werden muss.
Fazit: Eine 1000-teilige Schaltung mit rekursiven Funktionen inklusive Rückkopplung einfach mal so berechnen zu wollen ist von vorne herein zum Scheitern verurteilt.
Du musst also entweder einen Weg finden die Anzahl der rekursiven Aufrufe zu reduzieren (was aber nur einer Behandlung der Symptome entspricht), oder du implementierst das Ganze nochmal iterativ.
|
|
|
|
|
Danke, ich versteh zwar wie du das meinst, ABER: ich hab gar keine Ahnung wie ich das umsetzen kann.
Den einzigen Loesungsansatz, den ich mir vorstellen kann ist, dass das Gatter mitzaehlt, wie oft es seinen ausgang aendert.
Hat es den Ausgang oft genug geaendert, dann soll es bitte aufhoeren.
Und genau da muss ich ja bei jedem Aufruf kontrollieren, ob das der Fall ist
um die Endlosschleife zu verlassen.
Der andere Ansatz ist im Prinzip der selbe, nur da lasse ich zaehlen, wie oft sich eine Signalleitung aendert...
Ich gehe mal davon aus, dass der Ansatz richtig ist, aber die Umsetzung sehr schlecht ist.
Aus den oben aufgefuehrten Link konnte ich ich fuer iterative Varianten folgende Aenderung realisieren (Obwohl ich nicht ueberzeugt bin, dass diese Loesung iterativ ist, meines erachtens stellt diese Variante kaum eine Veraenderung dar).
kurze Einfuerung: Ich habe eine Superklasse Gate, aus der ich alle geforderten Gatter ableite. In Gate habe ich also
protected final static int maxBerechnung = 5000; //so oft darf das Gatter berechnen
protected int aktBerechnung; //so oft wurde berechnet
Wenn ich jetzt z.B. den Ausgang eines Buffers berechnen will, dann solange bis es nicht mehr notwendig ist. Die Methode sieht also so aus:
public void ausgangBerechnen(...){
while (super.maxBerechnung > super.aktBerechnung) {
super.aktBerechnung++;
...
}
}
Ich kann also so auch nur recht kleine maxBerechen fahren.
Koennte mir einer bitte einen anderen ansatz empfehlen?
bzw. wie kann ich diese Kontrolle, ob ich oft genug berechnet habe iterativ durchfuehren?
mfg
Chochalski
|
|
|
|
|
Status: |
(Antwort) fertig | Datum: | 17:51 Di 15.05.2007 | Autor: | Frank05 |
> Aus den oben aufgefuehrten Link konnte ich ich fuer
> iterative Varianten folgende Aenderung realisieren (Obwohl
> ich nicht ueberzeugt bin, dass diese Loesung iterativ ist,
> meines erachtens stellt diese Variante kaum eine
> Veraenderung dar).
Der Code, den du hier angegeben hast, ist auch nicht relevant für die Entscheidung ob iterativ oder rekursiv.
> kurze Einfuerung: Ich habe eine Superklasse Gate, aus der
> ich alle geforderten Gatter ableite. In Gate habe ich also
>
> protected final static int maxBerechnung = 5000; //so oft
> darf das Gatter berechnen
> protected int aktBerechnung; //so oft wurde berechnet
>
> Wenn ich jetzt z.B. den Ausgang eines Buffers berechnen
> will, dann solange bis es nicht mehr notwendig ist. Die
> Methode sieht also so aus:
>
> public void ausgangBerechnen(...){
> while (super.maxBerechnung > super.aktBerechnung) {
> super.aktBerechnung++;
> ...
> }
> }
Die entscheidende Frage ist nun, ob ein weiterer Aufruf von ausgangBerechnen(..) in dem Teil mit dem ... vorkommt. So wie das hier steht gibt es nämlich keinen StackOverflow. Das ist nur eine simple Schleife und wird für sich genommen keinerlei Probleme bereiten.
> Ich kann also so auch nur recht kleine maxBerechen fahren.
> Koennte mir einer bitte einen anderen ansatz empfehlen?
> bzw. wie kann ich diese Kontrolle, ob ich oft genug
> berechnet habe iterativ durchfuehren?
Wie wäre es mit etwas in der folgenden Art:
1: |
| 2: | while (++berechnungsSchritt <= maxBerechnungen && !keine_aenderung) {
| 3: | keine_aenderung = true;
| 4: | /* Update des kompletten Netzes um einen Schritt,
| 5: | also neues Ergebnis für jedes Gatter hier auf einen
| 6: | Schlag berechnen. Wenn sich etwas geändert hat wird
| 7: | keine_aenderung auf false gesetzt. */
| 8: | }
|
|
|
|
|