Fehlermeldung "Zu wenig Arbeitsspeicher"
Hallo Zusammen,
in einer Funktion von mir, die dazu dient aus einer SQL-Anweisung (als Stringliste) alle Kommentare zu entfernen, tritt sporadisch der Fehler "Zu wenig Arbeitsspeicher" auf. Leider kann ich nicht nachvollziehen, wo und warum das geschieht. Evtl. hat einer von Euch ja mehr Überblick und sieht auf den 1.Blick, unter welchen Umständen das passieren könnte bzw. ob ich ansich einen schweren Fehler begehe (evl. die Übergabe der Stringliste?).
Delphi-Quellcode:
Gruß
function DeleteComments(TempList:TStringList):TStringList;
var beg,en,i : integer; begin for i:=0 to TempList.Count-1 do if Trim(Copy(TempList[i],1,2))='--' then TempList[i]:='/*'+Copy(TRIM(TempList[i]),3,Length(TempList[i]))+'*/'; while pos('/*',TempList.Text) <> 0 do begin beg:=pos('/*',TempList.Text); en:=pos('*/',TempList.Text); if en=0 then en:=Length(TempList.Text); TempList.Text:=copy(TempList.text,1,beg-1)+ copy(TempList.Text,en+2,Length(TempList.Text)); end; Result:=TempList; end; Micha |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Ich glaube nicht, dass es an der Übergabe liegt.
Aber warum gibst Du die Instanz von Templist zurück? Wenn Du doch eh auf der Liste Veränderungen vornimmst, dann brauchst Du sie nicht zurückzugeben.
Delphi-Quellcode:
procedure Machwas;
var myListe: TStringList; begin myListe := TStringList.Create(); try // hier noch die liste füllen... // der Aufruf myListe := DeleteComments(myListe); // ist vollkommen identisch mit: DeleteComments(myListe); finally if Assigned(myListe) then FreeAndNil(myListe); end; end; |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Ok, schon geändert.
Macht es eigentlich einen Unterschied ob man:
Delphi-Quellcode:
oder
procedure DeleteComments(TempList:TStringList);
Delphi-Quellcode:
procedure DeleteComments(var TempList:TStringList);
deklariert. Gruß Micha |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Ja, denn bei der Übergabe als var kannst Du theoretisch sogar die Referenz ändern, d.h. wenn Du ListBox.Items übergibst, könntest Du auf ComboBox.Items referenzieren. Daher habe ich persönlich mir angewöhnt, Objektinstanzen immer als const-Parameter zu übergeben.
|
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Alles klar und vielen Dank.
Aber woher könnte denn nun die Fehlermeldung kommen? |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Übergibst Du jetzt als const-Parameter?
|
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Für mich gerade logische Erklärung:
Du benutzt ziemlich intensiv 'copy'. Das erzeugt eine String-Variable. Da Du das Ergebnis sofort verwendest und nirgends 'manuell' zwischenspeicherst, muss Delphi die Variable ja irgendwo hinpacken. Jedes einzelne Copy braucht also Speicher, der solange belegt wird, bis die Funktion beendet ist. (Kann auch sein, dass ich mich hier irre. Ich kenne die interna dafür nicht gut genug). Möglicherweise hilft es, mit temporären Variablen zu arbeiten, und zuerst die Rückgabe von Copy dort abzulegen und dann erst dann zu vergleichen, als das in einem Schritt zu machen. Somit hat der Wert der aus Copy rauskommt einen genau definierten Platz im Speicher und überschreibt immer den vorherigen, anstelle neuen Platz zu benötigen (wie gesagt ohne Gewähr für die Richtigkeit meiner Annahme). |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Klingt logisch.
|
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Zitat:
|
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Ja, das hab ich geändert. Das Problem ist aber, daß der Fehler bei mir selbst sowieso noch nie aufgetreten ist; also nicht vor und auch nicht nach der jetzigen Änderung. Der Fehler tritt nur sporadisch (1-5 mal pro Monat) bei dem Benutzer der Software auf und so ist das schwierig herauszufinden, ob es was gebracht hat.
Du meinst aber also schon, daß es daran gelegen haben könnte? Gruß Micha |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Versuch es mal mit Zwischenspeichern der Teilstrings wie von Phoenix angesprochen.
|
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
@DeddyH: Ich hatte Phoenix' Antwort noch nicht gelesen, als ich Dir geantwortet habe, sorry.
@Phoenix: Kannst Du mir dafür mal ein Beispiel geben? Ich glaub ich verstehs gerade nicht so richtig ... habe um die Uhrzeit glaube immer meinen Tiefpunkt :-) Gruß Micha |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Also ich würde so vorgehen:
1.) alle Zeilen, die mit '--' beginnen enfernen.
Delphi-Quellcode:
2.) TempList.Text ist Stringvariable kopieren, damit arbeiten/ändern und Ergebnis zurückkopieren.
for i:=TempList.Count-1 downto 0 do // rückwärts zählen !!
if Trim(Copy(TempList[i],1,2))='--' then TempList.Delete(i); (so wie Phoenix das erklärt hat) >> daß es daran gelegen haben könnte ? Wichtig ist das Bottom-Up Design. Die Procedure wird solange umgebaut/verbessert bis mehrere Programmierer sie für gut und richtig befinden. Das gibt Sicherheit und eine gute Basis für ein Projekt. |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Zitat:
|
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Ich hab jetzt mal alles so geändert, wie ich es verstanden hab und bitte hiermit um erneute Überprüfung (ganz im Sinne des Bottom-Up Designs)
Delphi-Quellcode:
Gruß
function DeleteCommentsNeu(const SQLLines:TStringList):Boolean;
var beg,en,i,Laenge : integer; var Temp,begStr,enStr:String; begin Laenge:=Length(SQLLines.Text); for i:= SQLLines.Count-1 downto 0 do Begin Temp:=Copy(Trim(SQLLines[i]),1,2); if Temp='--' then SQLLines.Delete(i); end; Temp:=SQLLines.Text; while (pos('/*',Temp) <> 0) and (pos('*/',Temp)>pos('/*',Temp)) do begin beg:=pos('/*',Temp); en:=pos('*/',Temp); if en=0 then en:=Length(Temp); begStr:=copy(Temp,1,beg-1); enStr:= copy(Temp,en+2,Length(Temp)); Temp:=begStr+enStr; end; SQLLines.Text:=Temp; Result:=Length(SQLLines.Text)<>Laenge; end; Micha |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Zitat:
Zitat:
|
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Sieht auf den ersten Blick gut aus, allerdings löschst Du keine einzeiligen Kommentare am Zeilenende.
[edit] @Grumpy: das ist mir später dann auch aufgefallen :lol: [/edit] |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
So sieht's tatsächlich aus. Danke, ich werd's gleich noch ändern.
Gruß Micha |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
So, fertig:
Delphi-Quellcode:
Gruß
function DeleteCommentsNeu(const SQLLines:TStringList):Boolean;
var beg,en,i,Laenge : integer; var Temp,begStr,enStr:String; begin Laenge:=Length(SQLLines.Text); for i:= SQLLines.Count-1 downto 0 do Begin beg:=pos('--',SQLLines[i]); if beg <> 0 then Begin if beg=1 then SQLLines.Delete(i) else SQLLines[i]:=Copy(SQLLines[i],1,beg-1); end; end; Temp:=SQLLines.Text; while (pos('/*',Temp) <> 0) and (pos('*/',Temp)>pos('/*',Temp)) do begin beg:=pos('/*',Temp); en:=pos('*/',Temp); if en=0 then en:=Length(Temp); begStr:=copy(Temp,1,beg-1); enStr:= copy(Temp,en+2,Length(Temp)); Temp:=begStr+enStr; end; SQLLines.Text:=Temp; Result:=Length(SQLLines.Text)<>Laenge; end; Micha |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Kleiner Vorschlag:
Delphi-Quellcode:
Und
for i:= SQLLines.Count-1 downto 0 do
Begin beg:=pos('--',Trim(SQLLines[i])); Zitat:
|
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Hallo Micha,
ich vermute das ist nicht so gewollt: Zitat:
und ob es hiermit keinen Ärger gibt weiß ich auch nicht: Zitat:
Delphi-Quellcode:
es gibt Clients, die so etwas verdauen können. In diesem Fall handelst Du Dir durch das löschen der Zeilenkommentare '--' eine Menge Ärger ein, weil dann nur noch "Select Daten" übrig bleibt.
Select Daten
/* ab hier jetzt auswählen -- ,daten1 -- ,daten2 -- ,daten3 -- Bitte das Datumsformat beachten !! */ from ....... Gruß K-H |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
:stupid:
|
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Hallo p80286,
1. Ich denke durch die Bedingung
Delphi-Quellcode:
in der WHILE-Schleife, sollte die IF-Anweisung
(pos('*/',Temp)>pos('/*',Temp))
Delphi-Quellcode:
gar nicht auslösen - ist quasi eine Altlast.
if en=0 then en:=Length(Temp);
2. Warum sollte die Zeile
Delphi-Quellcode:
Ärger bringen?
enStr:= copy(Temp,en+2,Length(Temp));
3. Da geb ich Dir recht und werd mir was überlegen. Gruß Micha |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Hallo spaxxn,
na und? Gruß Micha |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Hallo Micha,
da en+2 größer als length(temp) ist. In der Vergangenheit bin ich damit mal vor die Wand gelaufen darum benutze ich immer
Delphi-Quellcode:
um ganz sicher zu gehen
if startpos<=length(daten) then
dummy:=copy(daten,startpos,lange);
Delphi-Quellcode:
oder
if (startpos>length(daten)) and (lange>0) then
dummy:=copy(daten,startpos,lange);
Delphi-Quellcode:
Gruß
if startpos+lange-1<=length(daten) then
dummy:=copy(daten,startpos,lange); K-H |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Hallo,
Zitat:
Vorschlag für die Kommentare mit /* */ von hinten nach vorne durch die Liste laufen und wenn ein */ gefunden wurde in der Zeile alles bis einschließlich */ löschen, dann bis nach vorne weiter alle Zeilen löschen, in denen kein /* vorkommt bis zu der Zeile in der /* vorkommt und in der Zeile alles ab dem /* löschen. Auch sowas ist möglich:
SQL-Code:
Stelle mir das in etwa so vor (nicht getestet!!!)
Select
Daten /* ab hier jetzt auswählen -- ,daten1 -- ,daten2 -- ,daten3 -- Bitte das Datumsformat beachten !! */ from .......
Delphi-Quellcode:
Du sparst dadurch viele pos auf die ganze Stringliste. Pos ist immer nur für eine Zeile erforderlich, Du brauchst halt zusätzlich einen Schalter zum merken, ob Du in einem Kommentar bist oder nicht.
bKom := false;
for i := SQLLines.Count-1 downto 0 do begin iPosEnde := Pos('*/',SQLLines[i]); if iPosEnde > 0 then begin s := Copy(SQLLines[i],1,iPosEnde - 1); SQLLines[i] := s; bKom := True; end else begin iPosAnfang := Pos('/*',SQLLines[i]); if iPosAnfang > 0 then begin s := Copy(SQLLines[i],iPosAnfang - 1, length(SQLLines[i]) - iPosAnfang); SQLLines[i] := s; bKom := False; end; end; if bKom then SQLLines.Delete(i); end; for i := SQLLines.Count-1 downto 0 do begin bKom := Copy(Trim(SQLLines[i]),1,2) = '--'; If bKom Then SQLLines.Delete(i) end; Stephan PS.: Dein Speicherproblem muss aber nicht hier liegen, mag sein, das viel Speicher gebraucht wird. Versuche trotzdem heraus´zufinden, was auf dem Rechner zum Zeitpunkt des Fehlers sonst noch so alles unterwegs ist, eventuell läuft ja zuweilen parallel noch ein anderer "Speicherfresser". Im Zweifelsfalle versuche in einem Try-Except-Block herauszubekommen, wie groß die Stringliste ist, wieviel Speicher Dein Programm braucht und wieviel Speicher andere Programme brauchen. |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Hallo zusammen,
ich habe einmal zusammengekramt wie groß unsere SQL-Scripte so sind. Die meisten liegen bei ca. 1-5K wenige haben bis zu 50..60K und ganz wenige mehr als 300K. Die enthalten dann aber auch gleich ein paar Daten . Die 300K sollten eigentlich überhaupt kein Problem sein. Wenn ich mich richtig erinnere werden daraus ca. 600K wenn die Datei geladen ist. Da bleibt eigentlich noch genügend Platz für andere Daten und Programme. (wenn im fraglichen Script allerdings eine vollständige DB-Generierung + Daten steckt, dann allerdings) Gruß K-H |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Ich hab da auch mal einen Versuch gestartet (könnte aber bei sehr großen Skripten auch ein Speicher- oder Performanceproblem haben):
Delphi-Quellcode:
procedure StripSQLComments(const sl: TStrings);
const cmBegin = '/*'; cmEnd = '*/'; cmOneLine = '--'; var i,start,ende: integer; temp: string; begin sl.BeginUpdate; try //Mehrzeilige Kommentare entfernen temp := sl.Text; start := Pos(cmBegin,temp); ende := Pos(cmEnd,temp); while (start > 0) and (ende > start) do begin System.Delete(temp,start,ende - start + Length(cmEnd)); start := Pos(cmBegin,temp); ende := Pos(cmEnd,temp); end; sl.Text := temp; //Einzeilige Kommentare und Leerzeilen entfernen for i := sl.Count-1 downto 0 do begin start := Pos(cmOneLine,Trim(sl[i])); case start of 0: if Length(Trim(sl[i])) = 0 then sl.Delete(i); 1: sl.Delete(i); else begin temp := sl[i]; System.Delete(temp,start,Length(temp)); sl[i] := temp; end; end; end; finally sl.EndUpdate; end; end; |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Vielen Dank für Eure viele Antworten und Anregungen, ich werde mir alles im Laufe des Tages mal anschauen und meine Fkt. evtl. entsprechend ändern.
Gruß Micha |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Hallo,
mir ist da diese Nacht noch was eingefallen: Meine oben "aufgeführte" Logik(?) scheitert bei
SQL-Code:
Daher noch ein Vorschlag:
Select
Daten /* ab hier jetzt auswählen -- ,daten1 -- ,daten2 -- ,daten3 -- Bitte das Datumsformat beachten !! */ from where spalte1 = 'xyz' /* das ist jetzt Kommentar */ and spalte2 = 42 and datum > '01.01.1900' -- das ist ein Datum für irgendwaszumausschließen per globaler Ersetzung alle /* in "Zeilenvorschub /* Zeilenvorschub" ändern, ebenso alle */ in "Zeilenvorschub */ Zeilenvorschub" ändern, damit hast Du dann alle Kommentare der *-Sorte am Zeilenanfang, hierdurch dürfte das finden der Kommentare und das Erkennen von Anfang und Ende einfacher werden. Probleme bleiben dennoch:
SQL-Code:
Da scheitert auch diese Logik. Wie weit musst Du das mit dem Rauswerfen der Kommentare treiben? Und warum müssen sie raus?
Select * from tabelle where sqlstring like '%/*%'
Bei Oracle bekämst Du da noch ein zusätzliches Problem: Hinweise an den Optimizer stehen nämlich auch in Kommentaren und die rauszuwerfen wäre suboptimal. Wahrscheinlich mache ich hier aber gerade Baustellen auf, die ruhig zugelassen werden können. Und ich befürchte, dass hat alles nichts mit dem Speicherproblem zu tuen. Wie groß sind die von Dir zu bearbeitenden Statements und wieviele sind es? Stephan |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Zitat:
|
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
So, ich habe mir alles mal angeschaut und mich entschlossen bei meiner Logik zu bleiben, aber Eure Einwände mit einzubeziehen.
@nahpets: Deine Prozedur hat leider scheinbar auch einige Fehler, jedenfalls liefert Sie nicht immer ein korrektes Ergebis. z.B. bei
SQL-Code:
Aber es geht ja hier nicht um Deine Prozedur, sondern um meine ;-) Trotzdem Danke für Deine Anregungen.Select * /* Daten -- ,daten1 -- ,daten2 -- ,daten3 */ from Deine Anmerkungen hinsichtlich Oracle sind zwar richtig, aber in meinem Fall brauch ich das wohl nicht zu beachten, da ich nur mit dem MS-SQL-Server arbeite. Das mit:
SQL-Code:
ist aber allerdings schon ein Problem. Ich denke aber ich kann das vernachlässigen, zumindest bis zur 1.Meldung eines Kunden, der nach diesem String selektieren möchte ;.)
Select * from tabelle where sqlstring like '%/*%'
Die Kommentare müssen raus, da sie beim Zugriff mit ADO unter gewissen Umständen zu Problemen führen und ich nicht weiß was mein Kunde in seine SQL-Skripte alles reinschreibt. @DeddyH: Deine Prozedur funktioniert hervorragend, ist aber deutlich langsamer (bis zu 10x) als meine, sobald es sich um große SQL-Skripte mit vielen Zeilen handelt, ansonsten ist sie schneller. @Alle Ansonsten noch mal allen vielen Dank. Ich hoffe die Optimierungen (besonders die COPY-Problematik) haben geholfen und ich sehe den Fehler nie wieder in meinen Fehlerprotokollen. Gruß Micha |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Hallo,
Zitat:
Zitat:
Bin ja nicht neugierig :wink:, aber wie sieht jetzt Deine Lösung aus? Stephan |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Hallo,
ich hab nichts weiter mehr geändert, nur die Reihenfolge der Blöcke vertauscht, die überflüssige IF-Anweisung raus und noch ein try/finaly dazu.
Delphi-Quellcode:
Gruß
function DeleteCommentsNeu(const SQLLines:TStringList):Boolean;
var beg,en,i,Laenge : integer; var Temp,begStr,enStr:String; begin Laenge:=Length(SQLLines.Text); SQLLines.BeginUpdate; Try //Mehrzeile Kommentare Temp:=SQLLines.Text; while (pos('/*',Temp) <> 0) and (pos('*/',Temp)>pos('/*',Temp)) do begin beg:=pos('/*',Temp); en:=pos('*/',Temp)+2; begStr:=copy(Temp,1,beg-1); enStr:= copy(Temp,en,Length(Temp)); Temp:=begStr+enStr; end; SQLLines.Text:=Temp; //Einzeilige Kommentare for i:= SQLLines.Count-1 downto 0 do Begin beg:=pos('--',SQLLines[i]); if beg <> 0 then Begin if beg=1 then SQLLines.Delete(i) else SQLLines[i]:=Copy(SQLLines[i],1,beg-1); end; end; Finally SQLLines.EndUpdate; End; Result:=Length(SQLLines.Text)<>Laenge; end; Micha |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Hallo,
einen hätt' ich noch, Du ermittelst die Beginn- und Endepositionen mehrfach, das kann bei großen Datenmengen schon ein bisserl dauern:
Delphi-Quellcode:
Das könnte eventuell schneller werden.
//Mehrzeile Kommentare
Temp := SQLLines.Text; beg := pos('/*',Temp); en := pos('*/',Temp) + 2; while (beg <> 0) and (en > beg) do begin begStr := copy(Temp,1,beg - 1); enStr := copy(Temp,en,Length(Temp)); Temp := begStr + enStr; beg := pos('/*',Temp); en := pos('*/',Temp) + 2; end; SQLLines.Text := Temp; Stephan |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Dazu fällt mir noch was ein, ich schreib mal Kommentare in den Code...
Zitat:
|
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
"beg" kann nicht 0 sein, daß wird doch schon in der WHILE-Bedingung abgefangen.
Das mit dem PosEx werde ich noch ändern, Danke für den Hinweis. Gruß Micha |
Re: Fehlermeldung "Zu wenig Arbeitsspeicher"
Du hast Recht, ich hatte mir nur das Snippet im letzten Post angeschaut, da ist die umfassende Whileschleife ja nicht mit drin, deswegen hab ichs übersehen.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:28 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz