PDA

Vollständige Version anzeigen : Nicht genügend Stapelspeicher


Acham
24.01.2008, 09:34
Hallo allerseits,

ich bekomme die Fehlermeldung "Nicht genügend Stapelspeicher".
(Die Suche im Forum nach o.g. Fehlermeldung hat mir nicht viel weitergeholfen)

Beschreibung:
In einer DB habe ich ca. 20 Paradox und DBase Datenbanken verknüpft. Diese
Datenbanken sollen in ACC-tabellen kopiert werden.

Der Start verläuft über ein Popup-Formular.

So nun zu der eigentlichen Problembeschreibung.
Diese Aktualisierung funktionierte schon jahrelang auf mehreren Rechnern (ohne Probleme), egal ob WIN 98, Win XP SP2, mit Off2000 SR oder ohne.
Meine Kollegin hat jetzt einen neuen Rechner bekommen (1,5 GB RAM)
und dort kommt nach ungefähr der 6. Aktualisierung o.g. Fehlermeldung.

Diese Fehlermeldung kann ich mir überhaupt nicht erklären. Kann mir da jemand weiterhelfen?



Public Function Aktualisieren()
Dim varrueckgabe As Variant

varrueckgabe = SysCmd(acSysCmdSetStatus, "ArtikelLieferanten Aktualisieren")
fctArtikelLieferantenAktualisieren
varrueckgabe = SysCmd(acSysCmdSetStatus, "Warenart Aktualisieren")
fctWarenartAktualisieren
.
.
.
.

End Function

Function fctArtikelLieferantenAktualisieren()
CurrentDb.Execute "DELETE TBLArtikelLieferanten.* FROM TBLArtikelLieferanten;"
CurrentDb.Execute "INSERT INTO TBLArtikelLieferanten ( ARTNR, LIEFERNR, BESTELLNR, EKPREIS, RABATT, LIEFERZEIT, MINDESTMENGE, RABATTART, PREISEINHEIT, BESTELLTEXT, VERPACKUNGSEINHEIT ) SELECT ARTLIEF.ARTNR, ARTLIEF.LIEFER_NR, ARTLIEF.BESTELL_NR, fctkaufmannrunden((IIf([Währung]='EUR',[EK_PREIS],[EK_PREIS]/1.95583)),2) AS Feld1, [RABATT]/100 AS Ausdr1, ARTLIEF.LIEFERZEIT, ARTLIEF.MINDESTMENGE, ARTLIEF.Rabatt_Art, ARTLIEF.PR_EINHEIT, ARTLIEF.ANG_TEXT, ARTLIEF.VERP_EINHEIT FROM ARTLIEF;"
End Function

Function fctWarenartAktualisieren()
CurrentDb.Execute "DELETE TBLWarenart.* FROM TBLWarenart;"
CurrentDb.Execute "INSERT INTO TBLWarenart ( Warenart ) SELECT UCase([Warenart]) AS Ausdr1 FROM WARART;"
End Function

Grumbler85
24.01.2008, 09:58
Wäre es wohl möglich, dass du dort, wo du den Stapelüberlauf bekommst, sehr viel mehr Daten kopieren möchtest?
Ist das nämlich der Fall solltest du über die Benutzung von LIMIT (oder in Access glaube ich TOP) nachdenken, also einfach dafür sorgen, dass weniger Datensätze auf einmal kopiert werden.

Sascha Trowitzsch
24.01.2008, 10:48
Mit der Größe des RAM hat das nichts zu tun. Die Größe des Stacks (Stapelspeicher) legen die Anwendung und Windows fest.
Normal kommt diese Meldung nur, wenn der Stapel überläuft, was in VBA meist heißt, dass zuviele Funktionsaufrufe stattfanden, ohne dass zurückgekehrt wurde. Sowas passiert, wenn man Prozeduren rekursiv aufruft; also etwa Prozedur 1 ruft Prozedur 2 auf, und die Prozedur3, aber Prozedur 3 ruft wieder Prozedur 1 auf, so dass ein Kreislauf entsteht, in dem sich nie ein End Sub oder End Function ereignet. Die Rücksprungsadressen werden dabei auf den Stapel zwischengespeichert, der so immer größer wird.
Mit diesem Code, in dem Test1() ausgeführt werden sollte, lässt sich das nachstellen:
Dim i As Long

Sub Test1()
i = i + 1
Debug.Print i
Test2
End Sub

Sub Test2()
i = i + 1
Debug.Print i
Test1
End Sub

Aus deinem Code oben lässt sich nicht klar erkennen, ob sowas passieren könnte. Mag auch an fehlerhafter Installation von Access liegen?
Mir fällt allerdings auf, dass die Funktion fctkaufmannrunden() in den Insert-Abfragen drin steckt. Ersetze die mal testweise durch ROUND().

Ciao, Sascha

Acham
24.01.2008, 13:33
Vielen Dank für eure Antworten.

Wie limitiere ich das Kopieren (zu LIMIT oder TOP habe ich in der Hilfe nichts gefunden) ? Die größte Datenmenge die in eine Tabelle kopiert werden sind ca. 110.000 Datensätze.

Das mit dem ROUND habe ich ausprobiert, aber es gab keine Veränderung.
Die Funktion fctkaufmannrunden ist nur dazu da, dass Werte kaufmännisch gerundet werden.
Rekursive Aufrufe gibt es auch nicht, denn ich habe, wie bei meinem Code-Beispiel, nur die eine Hauptfunktion Aktualisieren() und dann die anderen Unterfunktion genauso aufgebaut wie die anderen 2 Funktionen.

Ich habe auch mal die Reihenfolge der Aktualisierungen vertauscht, und es gab außer der Fehlermeldung mit dem Stapelüberlauf eine neue Fehlermeldung "1 Parameter wurde erwartet oder es wurden zu wenig übergeben".

Ich würde sagen, dass an diesem PC Access nach einer bestimmten Anzahl von Aktualisierungen abbricht ???, denn durch die Änderung der Reihenfolge der Aktualisierungen, fällt auf dass die Meldung mit dem Stapelüberlauf bei jeweils anderen Aktualisierungen kommt, die Meldung mit dem Parameter ist zufällig.

Anscheinend komme ich wohl um eine Neuinstallation nicht drumherum, denn die Aktualisierung funktioniert ja auf anderen PC's einwandfrei.

Gibt es in der Registrierung Werte zur Stapelgröße?

Sascha Trowitzsch
24.01.2008, 16:45
Gibt es in der Registrierung Werte zur Stapelgröße?
Das steht nicht in der Registry.
Die Anwendung sieht pro Thread einen Wert von sich aus vor, der von außen nicht zu beeinflussen ist. Beim Erzeugen von Threads (CreateThread-API) der Anwendung muss dazu ein vom Standard 1 MB abweichender Wert angegeben werden. ( http://msdn2.microsoft.com/en-us/library/ms686774(VS.85).aspx )Ich weiß allerdings nicht, woher VBA seinen Speicher bezieht, ob es also den Stack mit Access teilt, oder einen eigenständigen hat. Sprich, ob die Aktionen unter Access/JET auch den unter VBA verfügbaren Seicher beeinflussen.
In meiner Testroutine oben ist nach 6800 Aufrufen Schluss. Daraus lässt sich aber nicht der Speicherbedarf errechnen, weil unklar ist, was VBA bei einem Funktionsaufruf alles auf den Stack rettet.

Nach deiner Beschreibung der Prozedur scheint es sich mir doch um eine Macke von VBA zu handeln, die evtl. mt Reparaturinstallation zu beheben geht. Ist aber nicht auszuschließen, dass der schwarze Peter auch bei Windows liegt.
Ich kann leider nicht mehr dazu sagen.
Hier noch ein Link:
http://msdn2.microsoft.com/en-us/library/0ctsw64a(VS.80).aspx
Kannst auch nach "out of stack space vba" googlen.

Ciao, Sascha

punchbyte
23.10.2008, 13:29
Ich hatte den gleichen Effekt kürzlich bei einer Kopierfunktion und habe folgende Ursache gefunden:

Wenn ich eine beliebige Anzahl von Datensätzen kopiere, bekomme ich den Laufzeitfehler nicht. Wenn ich aber mit "Do ... Loop" mehrere Datensätze nacheinander bearbeiten will, aber tatsächlich nur ein einziger Datensatz vorhanden ist, die Schleife also eigentlich überflüssig ist, dann tritt bei mir der Fehler auch auf.

WeinGeist
23.10.2008, 16:57
Das ist ein ziemlich mühsamer Fehler. Habe ich manchmal auch wenn die Anwendung lange läuft, bzw. viele Daten mittels Recordsets bearbeitet werden.

Ein restlos klares Muster konnte ich aber, ausser bei nem Rekursiven aufruf wie von Sascha erwähnt, noch nicht nachvollzieh.

Ich vermute, dass Access irgend etwas nicht sauber ausm Speicher löscht. Ich habe bei gewissen Aktionen, trotz sauberen Close-Methoden und Set Nothing immer ein bissel mehr Ram-Auslastung im TaskManager. Bei X-Aktionen und wenn die RAM ca ungefähr über 120MB geht bekomme ich diesen Fehler.

Überprüfe auf alle Fälle ob du recordset.Close immer ausführst und möglichst bald auch das Set nothing.

Wo ich meine ihn auch schon gehabt zu haben ist bei der Verwendung von bissel umfangreicheren Queries wenn Access sie nimmer peilt und den Fehler "zu Komplex" feuert wenn man sie in Formulare verwedet, als abfrage aber noch funktionieren. Da lags dann meistens an Outer-Join Verknüpfungen mit NullWerten im ForeignKey. In VBA in der Verwendung von Recordsets wurde dann öfter der Stapelspeicherfehler gefeuert, wenn ich das richtig in Erinnerung habe.

Damit zusammen hängt noch ein anderer Fehler mit den geöffneten Datenbanken, der tritt auch häufig in Verbindung mit den Recordsets und dem Stapelfehler auf, und zwar dann, wenn sie nicht sauber mit Close geschlossen wurde.

Alles in allem konnte ich aber wie erwähnt noch kein wirkliches Muster erkennen ausser das es eben "häufig" mit der Verwendung von Recordsets und CurrentDb irgendwie zusammenhängt. Durch programmtechnische Änderungen kriegt man ihn aber meistens irgendwie weg indem man einfach nen anderen weg geht sofern irgendwie möglich. Beheben lässt es sich glaub leider auch nur mit dem Neustart der DB.

Marsu65
24.10.2008, 02:21
Schuss ins Blaue:
Bei Verwendung von CurrentDb wird ja jedes mal eine Instanz der Datenbank erzeugt. Ob die Instanz in diesem Fall erhalten bleibt (soll angeblich nur beim Erstellen von Recordsets so sein) und ob dabei etwas im Stack hängenbleibt, keine Ahnung.
Alternativ könntest du es jedenfalls mit
DBEngine(0)(0) oder aber mit
Dim db as Database
set db = CurrentDb
...
db.Execute
...
set db = Nothing
versuchen ?

Acham
24.10.2008, 15:43
Vielen Dank Marsu65 für deine Vorschläge.
Der besagte PC (von meiner Kollegin) hat jetzt nichts mehr mit den Aktualisierungen zu tun.
Deshalb kann ich deine Vorschläge auch nicht ausprobieren.
Auf meinem PC funktioniert ja die Aktualisierung ohne Probleme. Aber ich werde deine Vorschläge berücksichtigen, falls ich bei einem PC wieder mal vor diesem Problem stehen sollte.