![]() |
Service braucht immer mehr Speicher!!!!??????
Hallo!
Ich habe einen Windows-Service geschrieben. Der funktioniert soweit auch wunderbar, allerdings braucht der immer mehr Speicher: Er fängt an mit ca. 2.000 K; nach ca. 5 Minuten ist er dann bei ca. 20.000 K Mit Debug hab ich inzwischen herausgefunden, dass es an einer TStringList liegt, die immer wieder gefüllt wird. Aber waraum? Denn nachdem ich die Daten entsprechend verarbeitet habe, sollte der Speicherplatz doch wieder freigegeben werden. (Ich verwende die Methode: List.Free;) Das sollte doch funktionieren, oder mach ich beim Freigeben des Speichers was falsch? Danke! Gruß Matthias |
Re: Service braucht immer mehr Speicher!!!!??????
Vielleicht hilft dir ja
Delphi-Quellcode:
Du könntest zusätzlich noch prüfen, ob du irgendwo speicher mit GetMem reservierst aber nicht wiederfreigibst.
FreeAndNil(List);
mfG mirage228 |
Re: Service braucht immer mehr Speicher!!!!??????
Super, es ist schonmal erheblich weniger geworden, aber er steigt weiter kontinuierlich. (Hatte auch noch ein FreeMem vergessen)
Gibt es evtl. eine Möglichkeit, zu überwachen, welche Variablen gerade im Speicher liegen und wieviel Platz die belegen? Schon mal vielen Dank! Gruß Matthias |
Re: Service braucht immer mehr Speicher!!!!??????
Benutzt du in deiner Stringliste auch Objekte?
Wenn ja immer dran denken, was die Help dazu sagt : Zitat:
|
Re: Service braucht immer mehr Speicher!!!!??????
Hi.
Ich hab irgendwo im Kopf rumschwirren, dass Programme sehr ungern den Speicher tatsächlich wieder frei geben. Auch nach einem x.free. Das Objekt ist dann zwar aus deinem Speicher entfernt, aber dein Programm gibt den Speicher nicht an Windows zurück. Wäre es vieleicht eine Möglichkeit statt immer eine neue Stringlist zu benutzen eine StringList zu verwenden und diese immer wieder zu löschen (sl.clear)? Dann hast du nur ein Objekt und die StringList braucht maximal so viel Speicher, wie der längste String, den du in ihr gespeichert hast (plus overhead). Korrigiert mich, wenn ich falsch liege. (FreeAndNil dürfte sich genauso verhalten, da es nichts anderes macht als die Referenz vor dem Freigeben auf nil zu setzen. Ich bevorzuge übrigens diese Methode um ein Objekt freizugeben.) |
Re: Service braucht immer mehr Speicher!!!!??????
Hallo!
Leider hat das alles nichts gebracht. Der Speicher wächst weiter. So langsam weiß ich echt nicht mehr, woran es liegt. Kann man sich die benötigte Speichergröße einer Variable zur Laufzeit anzeigen lassen? Gruß Matthias |
Re: Service braucht immer mehr Speicher!!!!??????
Hallo Matthias,
ich nehme an, Du arbeitest in Deinem Service mit einer (Endlos-)schleife. Kann es sein, dass Du die Stringliste in der Schleifer immer neu erzeugst und befüllst, aber nur ausserhalb der Schleife zerstörst? Ansonsten solltest Du uns ein bißchen was von Deinem Code zeigen. |
Re: Service braucht immer mehr Speicher!!!!??????
Also ich würde so vorgehen:
- ![]() - den Service zunächst nur als "normale" Anwendung laufen lassen (dies lässt sich bestimmt über bedingte Compilierung oder einen Startparameter managen) Beim Beenden der Anwendung gibt MemCheck die Speicherlecks aus. Kommerzielle Tools wie z.B. Boundschecker leisten noch mehr wie MemCheck, aber MemCheck ist wie der Author verspricht: "what you get is what you need". :thuimb: |
Re: Service braucht immer mehr Speicher!!!!??????
Hallo!
Werde die Tips gleich mal ausprobieren. @APP Nein, ich arbeite mit einem Timer. OnTimer wird dann immer eine Prozedur aufgerufen. Diese macht als erstes:
Delphi-Quellcode:
und als letztes:
List:= TStringList.Create;
Delphi-Quellcode:
Daran wirds wohl nicht liegen.
List.free;
Trotzdem danke! Gruß Matthias |
Re: Service braucht immer mehr Speicher!!!!??????
wie siehts aus mit der frage von @Smokey
haengst du in die Stringliste objekte? wenn ja muessen die explizit abgeraeumt werden. |
Re: Service braucht immer mehr Speicher!!!!??????
Hallo!
Nein, es werden lediglich Anweisungen wie: List.Add('String1'); ausgeführt. MemCheck hat auch nicht wirklich was gebracht. Gibt's keine Möglichkeit, sie die Größe von Variablen zur Laufzeit anzeigen zu lassen? Gruß Matthias |
Re: Service braucht immer mehr Speicher!!!!??????
Die Größe von Variablen dürfte wohl bekannt sein. Ein Integer hat immer 4 Byte, ein Shortstring immer 256 Byte usw. Es liegt schlicht und ergreifend daran, dass du irgendwo den Speicher nicht wieder frei gibst und ohne Code bleibt das hier ein rumgerate. :roll:
|
Re: Service braucht immer mehr Speicher!!!!??????
Also, der Fehler muß hier drin sein.
Funktionnen, die hier drin aufgerufen werden sind es definitiv nicht. Wäre klasse, wenn einer was findet:
Delphi-Quellcode:
Die Variablen Typ und Liste werden in einer aufrufenden Instanz erstellt und auch wieder freigegeben.
begin
typ.Add('Kopfzeile'); view:= 'Typ;Datum;Uhrzeit;Quelle;Kategorie;EventID;Benutzer;Computer;Nachricht'; // Kopfzeile festlegen liste.Add(view); // Kopfzeile speichern event:= OpenEventLog(nil, event_log_name); // Eventlog öffnen IF event = 0 THEN Application.MessageBox('EventLog konnte nicht geöffnet werden!', 'Fehler', 0) // Ausgabe einer Fehlermeldung ELSE BEGIN GetNumberOfEventLogRecords(event, gesamt_anzahl); // Anzahl der Logs ermitteln if gesamt_anzahl > 0 then BEGIN if anzahl > 0 // nicht alle Datensätze auswerten then alt_zahl:= gesamt_anzahl - (anzahl - 1) // Anzahl der zu lesenden Logs auswerten else GetOldestEventLogRecord(event, alt_zahl); // Ältesten Log ermitteln (wenn alle Einträge ermittelt werden sollen for counter:= gesamt_anzahl DOWNTO alt_zahl DO // Anzahl vorhandener EventLogs BEGIN realbuffsize:= 4096; getmem(pbuf, realbuffsize); ReadEventLog(event, 6, counter, pbuf, realbuffsize, read, read_next); // Nächstes Event_log wird ausgelesen; CASE pbuf^.EventType OF // EventTyp lesbar speichern EVENTLOG_ERROR_TYPE:BEGIN viewable.EventType:= 'Error'; typ.Add('1'); END; EVENTLOG_WARNING_TYPE:BEGIN viewable.EventType:= 'Warning'; typ.Add('2'); END; EVENTLOG_INFORMATION_TYPE:BEGIN viewable.EventType:= 'Information'; typ.Add('3'); END; EVENTLOG_AUDIT_SUCCESS:BEGIN viewable.EventType:= 'Success Audit'; typ.Add('4'); END; EVENTLOG_AUDIT_FAILURE:BEGIN viewable.EventType:= 'Failure Audit'; typ.Add('5'); END; END; source := next_pointer_step(pbuf, sizeof(pbuf^)); // Pointer auf den SourceNamen setzen SetString(viewable.SourceName, source, lstrlen(source)); // SourceNamen abspeichern inc(source, lstrlen(source) + 1); // Pointer auf den Computernamen setzen SetString(viewable.ComputerName, source, lstrlen(source)); // Computernamen speichern // Zeit ermitteln viewable.LocalTimeGenerated:= UnixTimetoFiletime(pbuf^.TimeGenerated);// Zeit, Datum auslesen und anschließend konvertieren FileTimeToLocalFileTime(viewable.localtimeGenerated, viewable.LocalTimeGenerated); FileTimeToSystemTime(viewable.localtimeGenerated, zeit); // Ist in dem Datensatz eine SID vorhanden if pbuf^.UserSidLength <> 0 then // Wenn ja, dann Namen raussuchen BEGIN LookUpAccountSid(source, next_pointer_step(pbuf, pbuf^.UserSidOffset), usrName, usrSize, domainName, domainSize, peuse); viewable.Username:= usrName; if not (viewable.Username = '') then // entsprechend speichern viewable.UserName := Format('%s', [usrName]) else viewable.UserName:= 'N/A'; END else viewable.UserName:= 'N/A'; // Username entweder vorhanden oder auf 'N/A' gesetzt error := RegOpenKeyEx(HKEY_LOCAL_MACHINE, PChar('SYSTEM\CurrentControlSet\Services\Eventlog\'+event_log_name+'\'+viewable.sourcename), 0, KEY_ALL_ACCESS, regkey); // Registrierung öffnen if error = ERROR_SUCCESS THEN BEGIN // Schlüssel in der Registrierung vorhanden h1:= nil; regbuffersize:= 1024; GetMem(h1, 1024); error:= RegQueryValueEx(regkey, 'EventMessageFile', nil, nil, PByte(h1), @regbuffersize); // Schlüssel auslesen if error = ERROR_SUCCESS THEN BEGIN // Zugehörigen DLL-Namen speichern & Nachrichtentext ermitteln SetString(viewable.SourceFile, PChar(h1), lstrlen(PChar(h1))); freemem(h1); viewable.MessageText:= geteventmessagetext(pbuf^.EventID, viewable.sourcefile, pbuf, viewable); // Nachrichtentext ins lesbare konvertieren view:=viewable.EventType+';'+Format('%2.2d/%2.2d/%4.4d', [zeit.wMonth, zeit.wDay, zeit.wYear])+';'+Format('%2.2d:%2.2d:%2.2d', [zeit.wHour, zeit.wMinute, zeit.wSecond])+';'+viewable.SourceName+';'; // Logstring anlegen if viewable.EventCategory = '' then viewable.EventCategory:= 'None'; view:= view+viewable.EventCategory+';'+inttostr(pbuf^.EventID)+';'+viewable.Username+';'+viewable.ComputerName+';'+viewable.MessageText+';'; liste.Add(view); // Logstring der Liste hinzufügen END // Zugehörigen DLL-Namen speichern & Nachrichtentext ermitteln ELSE BEGIN // Keine DLL-Datei in der Registry eingetragen view:=viewable.EventType+';'+Format('%2.2d/%2.2d/%4.4d', [zeit.wMonth, zeit.wDay, zeit.wYear])+';'+Format('%2.2d:%2.2d:%2.2d', [zeit.wHour, zeit.wMinute, zeit.wSecond])+';'+viewable.SourceName+';'; // Logstring anlegen if viewable.EventCategory = '' then viewable.EventCategory:= 'None'; hw:= next_pointer_step(pbuf, pbuf^.Stringoffset); viewable.MessageText:= 'KEINE DLL-DATEI VORHANDEN: '; if pbuf^.Numstrings < 1 then view:= 'Nicht erkennbare Daten' else BEGIN for j:=1 to pbuf^.Numstrings DO // Parameter im Nachrichtentext ersetzen BEGIN SetString(hs, hw, lstrlen(hw)); inc (hw, lstrlen(hw)+1); viewable.MessageText:= viewable.MessageText+hs; END; view:= view+viewable.EventCategory+';'+inttostr(pbuf^.EventID)+';'+viewable.Username+';'+viewable.ComputerName+';'+viewable.MessageText+';'; END; liste.Add(view); // Logstring der Liste hinzufügen Freemem(hw); END; RegCloseKey(regkey); END // Schlüssel in der Registrierung vorhanden ELSE // Kein Eintrag in der Registrierung vorhanden BEGIN // Keine DLL-Datei in der Registry eingetragen view:=viewable.EventType+';'+Format('%2.2d/%2.2d/%4.4d', [zeit.wMonth, zeit.wDay, zeit.wYear])+';'+Format('%2.2d:%2.2d:%2.2d', [zeit.wHour, zeit.wMinute, zeit.wSecond])+';'+viewable.SourceName+';'; // Logstring anlegen if viewable.EventCategory = '' then viewable.EventCategory:= 'None'; hw:= next_pointer_step(pbuf, pbuf^.Stringoffset); viewable.MessageText:= 'KEINE DLL-DATEI VORHANDEN: '; if pbuf^.Numstrings < 1 then view:= 'Nicht erkennbare Daten' else BEGIN for j:=1 to pbuf^.Numstrings DO // Parameter im Nachrichtentext ersetzen BEGIN SetString(hs, hw, lstrlen(hw)); inc (hw, lstrlen(hw)+1); viewable.MessageText:= viewable.MessageText+hs; END; view:= view+viewable.EventCategory+';'+inttostr(pbuf^.EventID)+';'+viewable.Username+';'+viewable.ComputerName+';'+viewable.MessageText+';'; END; liste.Add(view); // Logstring der Liste hinzufügen Freemem(hw); END; Freemem(pbuf); END; // FOR-Schleife END; END; CloseEventLog(event); end; Gruß Matthias |
Re: Service braucht immer mehr Speicher!!!!??????
Das ist ja Spaghetti-Code !!! :shock:
Und alles ohne Resource-Schutzblock (try...finally...end). Eine Zerlegung der Gesamtaufgabe in Unter- Funktionen/Proceduren wäre sehr sinnvoll. Ausserdem: GetMem innerhalb der Schleife for counter:= gesamt_anzahl DOWNTO alt_zahl DO ist nicht sinnvoll. Einmal ausserhalb der Schleife hätte auch gereicht. |
Re: Service braucht immer mehr Speicher!!!!??????
Hallo Matthias,
Zitat:
sehe, ist das nicht der, den Du im onTimer-Event benutzt (kein TStringList.Create gefunden). Wenn Dein Code im onTimer-Event zur Ausführung länger dauert als der eingestellte Timerintervall (oder wenn Dein Code wegen eines Fehlers hängt) wird ein neues onTimer-Event erzeugt, wo Dein Code wiederum ausgefüht wird usw usf... Ausser Dein 1. Befehl im onTimer-Event ist Timer1.Enabled := False und Dein letzter Befehl Timer1.Enabled := True, um mehrere "Timerinstanzen" zu verhindern. p.s. Über Ressourcenschutzblöcke solltest Du wirklich nachdenken :thuimb: |
Re: Service braucht immer mehr Speicher!!!!??????
Hallo!
Also, nein, es ist nicht die Funktion, die OnTimer aufgerufen wird. Die beginnt mit mytimer.enabled:= false ... Aufruf dieser Prozedur ... mytimer.enabled:= true; Der Speicherzuwachs ist allerdings innerhalb dieser Prozedur. Ok, das mit dem getMem in der Schleife ist geändert. (hat aber nichts am Speicherproblem geändert) Wie funktioniert das mit den Ressourcenschutzblöcken? Habe gerade erst mit Delphi angefangen und bin eigentlich schon stolz, überhaupt so weit gekommen zu sein. Vielleicht kann mir das ja mal gerade einer erklären, evtl. mit nem kleinen Beispiel. Danke! Matthias |
Re: Service braucht immer mehr Speicher!!!!??????
Hallo Mathias,
Zitat:
Zu den Ressourcenschutzblöcken bemühe mal die DP-Suche: ![]() Dann stosst Du z.B. auf: ![]() |
Re: Service braucht immer mehr Speicher!!!!??????
Hallo!
Werde den Code nicht posten, da, wie weiter oben schon beschrieben, der Speicherzuwachs nur in dieser Prozedur stattfindet =>Bei Aufruf der Prozedur: 2.324 =>Bei Verlassen der Prozudur: 2.648 Daher würde weiterer Quellcode nichts bringen. Aber da mal noch ne Frage zu den Ressourcenschutzblöcken. Welchen Vorteil bieten sie und wann sollte man die verwenden? DANKE! Matthias |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:22 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz