| Autor |
Beitrag |
molotov
      
Beiträge: 24
|
Verfasst: Mi 05.09.07 15:00
Hallo allerseits!
Ich habe bei meinem Projekt folgendes Problem:
Meine Client-Anwendung holt vom Server zyklisch Daten. Dies geschieht mit einem TIdUDPClient-Objekt:
Delphi-Quelltext 1: 2:
| UDPC.Send(Message); UDPC.ReceiveString(); |
Wenn ich meine Anwendung im Taskmanager beobachte, so wächst der Speicherbedarf um ca. 2KB pro Sekunde (wobei das nicht immer gleich ist, geht nach oben und wieder etwas hinunter) jedoch "wächst" das Programm permanent an. Beim Debugger konnte ich lokalisieren, dass es an der UDP-Kommunikation liegen muss.
Ich habe schon einige Speichermanager (MemCheck, MemProof, ...) probiert, doch leider nichts gefunden.
Könnt ihr mir bitte Ratschlage geben, woran das liegen könnte?
Moderiert von matze: Delphi-Tags hinzugefügt
|
|
Narses
      

Beiträge: 10185
Erhaltene Danke: 1261
W11x64
TP3 .. D7pro .. D10.2CE
|
Verfasst: Mi 05.09.07 17:21
Moin und  im Forum!
molotov hat folgendes geschrieben: | | Ich habe schon einige Speichermanager (MemCheck, MemProof, ...) probiert, doch leider nichts gefunden. |
Soll heißen: die alternativen MemoryManager haben kein Speicherleck gefunden? (auch schon FastMM4 probiert?)
molotov hat folgendes geschrieben: | | Wenn ich meine Anwendung im Taskmanager beobachte, so wächst der Speicherbedarf um ca. 2KB pro Sekunde (wobei das nicht immer gleich ist, geht nach oben und wieder etwas hinunter) |
Das ist nicht unbedingt ein Speicherleck, das kann durchaus das "normale" Verhalten einer Delphi-Anwendung sein, wenn man lange Strings verwendet... Kuckst du
molotov hat folgendes geschrieben: | | Dies geschieht mit einem TIdUDPClient-Objekt: |
Wenn du nicht auf die Indy-Kompo angewiesen bist, kannst du ja mal diese Alternative probieren; vielleicht geht´s damit ja besser?
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
molotov 
      
Beiträge: 24
|
Verfasst: Do 06.09.07 09:45
Danke erstmals für die Tipps!
- FastMM4 hat leider auch nichts gefunden
- Die Kommunikation mittels TUdpSockUtil hat leider auch keine Verbesserung gebracht.
Eine Frage bzgl. dem Hinweis auf die langen Strings:
Ich benutze eine Funktion um eine Anfrage an einen Server zu senden und die Antwort zu erhalten. Diese sieht (nach Umbau auf TUdpSockUtil) im Groben folgendermaßen aus:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| function TMain.udpsend(msg:string):string; var aw:string; vonIP:in_addr; begin ... main.UdpSockUtil1.SendText(msg_temp); f_standard_u.Wait(50); aw:=main.UdpSockUtil1.ReceiveText(vonIP); ... result:=aw; end; |
In einer übergeordneten Funktion wird diese folgendermaßen verwendet (Grobstruktur):
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| function operation(var xmldoc:IXMLDocument):string; var aw,Text:string; begin Text:='Anfrage'; aw:=main.udpsend(Text); xmldoc.XML.Text:=aw; end; |
Ist hier etwas grundlegend falsch? Könnte der String vom Server zu lange sein für das normale String-Objekt?
|
|
Narses
      

Beiträge: 10185
Erhaltene Danke: 1261
W11x64
TP3 .. D7pro .. D10.2CE
|
Verfasst: Do 06.09.07 10:03
Moin!
molotov hat folgendes geschrieben: | | FastMM4 hat leider auch nichts gefunden |
Dann hast du keinen Fehler gemacht - folglich ist das ein "normaler" Effekt des Memory-Managers bzw. der Compiler-Magic für lange Strings.
molotov hat folgendes geschrieben: | | Die Kommunikation mittels TUdpSockUtil hat leider auch keine Verbesserung gebracht. |
Halte ich für ein weiteres Indiz für die Compiler-Konzept-Theorie.
molotov hat folgendes geschrieben: | Eine Frage bzgl. dem Hinweis auf die langen Strings:
Ich benutze eine Funktion um eine Anfrage an einen Server zu senden und die Antwort zu erhalten. Diese sieht (nach Umbau auf TUdpSockUtil) im Groben folgendermaßen aus:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| function TMain.udpsend(msg:string):string; var aw:string; vonIP:in_addr; begin ... main.UdpSockUtil1.SendText(msg_temp); f_standard_u.Wait(50); aw:=main.UdpSockUtil1.ReceiveText(vonIP); ... result:=aw; end; | |
Das ist potenziell kaputt, das ist dir schon klar, oder?!  Entweder du verwendest das OnRead-Ereignis der Komponente oder du machst das thread-basiert (dann allerdings ohne die Kompo bzw. mit einer anderen, TUdpSockUtil ist nur ereignisorientiert), sonst weißt du ja gar nicht, ob der Server überhaupt geantwortet hat!
molotov hat folgendes geschrieben: | | Ist hier etwas grundlegend falsch? Könnte der String vom Server zu lange sein für das normale String-Objekt? |
"Falsch" ist da dran nix (mit Ausnahme der oben erwähnten Warte-Methode), allerdings ist das genau das (Funktionsergebnistyp String), was in dem gelinkten Beitrag auch die Ursache für den "Speicherhunger" war.  Mach doch mal den Umbau, wie dort beschrieben.
Abgesehen davon: von welchen Speichermengen reden wir denn überhaupt (also maximal)? Was hast du denn konkret für Größen beobachtet? Schonmal längere Zeit laufen gelassen und dann geschaut?
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
molotov 
      
Beiträge: 24
|
Verfasst: Do 06.09.07 10:22
Die wait-Anweisung hab ich nur nach Umstellung auf TUdpSockUtil eingebaut, da manchmal keine Antwort kam. Hab ich jetzt wieder rausgenommen (hab ich beim "alten"-Objekt auch nicht drinnen gehabt) und es hat sich nichts verändert.
Ja, ich habe schon probiert, mein Programm länger laufen zu lassen, es startet mit einer Speicherauslastung von ca. 10 MB und nach ein paar Stunden (4-5) ist es auf ca. 40 MB angewachsen, also es wächst permanent, jedoch kann es passieren, dass es konstant bleibt. (Das ist aber ein Ausnahmefall).
Nun habe ich probiert, in meiner Haupt-Schleife, in der Daten zyklisch abgefragt werden, nur eine Anfrage mehrmals (40x) hinereinander gleich direkt zu senden (ohne Unterfunktionen).
Das Programm läuft anscheinend konstant - Werde es mal länger laufen lassen.
edit: Programm meldete nach ca. 10 Minuten folgende Fehlermeldung:
"Windows-Socket-Fehler: Eine Nachricht, die über einen Datagrammsocket gesendet wurde, war für den internen Nachrichtenpuffer oder ein anderes Netzwerklimit zu gross, oder der Puffer für den Datenempfang war für das Datagramm zu klein (10040), auf API 'RecvFrom'"
|
|
Narses
      

Beiträge: 10185
Erhaltene Danke: 1261
W11x64
TP3 .. D7pro .. D10.2CE
|
Verfasst: Do 06.09.07 10:34
Moin!
molotov hat folgendes geschrieben: | | Die wait-Anweisung hab ich nur nach Umstellung auf TUdpSockUtil eingebaut, da manchmal keine Antwort kam. Hab ich jetzt wieder rausgenommen (hab ich beim "alten"-Objekt auch nicht drinnen gehabt) und es hat sich nichts verändert. |
Langsam  wir reden hier von zwei unterschiedlichen "Problemen":
a) Das Speicherhunger-Problem
b) Die Verwendung des TUdpSockUtil
Zu a) siehe unten, jetzt zu b): Es geht nicht um das Warten, sondern darum, direkt nach dem Senden schon mit einer Antwort zu rechnen und zu lesen! Es liegen erst dann Daten zum Lesen an, wenn das Ereignis OnRead eintritt!  Das Konzept Senden-und-sofort-oder-mit-Pause-Antwort-Lesen ist für den TUdpSockUtil nicht zutreffend, das ist thread-basierte Methode.
molotov hat folgendes geschrieben: | | Ja, ich habe schon probiert, mein Programm länger laufen zu lassen, es startet mit einer Speicherauslastung von ca. 10 MB und nach ein paar Stunden (4-5) ist es auf ca. 40 MB angewachsen, also es wächst permanent, jedoch kann es passieren, dass es konstant bleibt. (Das ist aber ein Ausnahmefall). |
Was ist nun mit den Tipps aus diesem Beitrag? Schon probiert, wenn nicht, warum?
molotov hat folgendes geschrieben: | | edit: Programm meldete nach ca. 10 Minuten folgende Fehlermeldung: |
Nimm mal besser wieder die Indy-Kompos, du verwendest den TUdpSockUtil eh nicht richtig...
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
OlafSt
      
Beiträge: 486
Erhaltene Danke: 99
Win7, Win81, Win10
Tokyo, VS2017
|
Verfasst: Do 06.09.07 13:38
Es gibt da so einen kleinen Trick, um festzustellen, ob das ein Memory Leak ist oder nur der Memory Manager:
Starte das Programm und notiere im Taskmanager abgelesene werte für den Speicherbedarf. Dann laß das Programm eine Weile laufen. Wenn genug Speicher "geschluckt" wurde, das Programm minimieren und wieder zurückholen.
Springen die Werte im Taskmanager wieder ungefähr auf die schon notierten zurück, ist es der Memory Manager.
_________________ Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
|
|
Gausi
      
Beiträge: 8554
Erhaltene Danke: 481
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Do 06.09.07 13:58
Vorsicht! Dann muss man aber im TM auch den "virtuellen Speicher" anzeigen lassen! Ich habe eine Anwendung, die bei mir ca. 40 MB verbraucht, ggf. auch das doppelte und nach einem Minimieren und Wiederherstellen nur noch vier oder fünf - und da habe ich kein Speicherleck. Der virtuelle Speicherbedarf bleibt aber in etwa gleich.
_________________ We are, we were and will not be.
|
|
molotov 
      
Beiträge: 24
|
Verfasst: Do 06.09.07 14:28
OlafSt hat folgendes geschrieben: | Es gibt da so einen kleinen Trick, um festzustellen, ob das ein Memory Leak ist oder nur der Memory Manager:
Starte das Programm und notiere im Taskmanager abgelesene werte für den Speicherbedarf. Dann laß das Programm eine Weile laufen. Wenn genug Speicher "geschluckt" wurde, das Programm minimieren und wieder zurückholen.
Springen die Werte im Taskmanager wieder ungefähr auf die schon notierten zurück, ist es der Memory Manager. |
Danke für den Hinweis!
Habe ich bereits probiert: Werte bleiben gleich. Seltsamerweise hab ich es heute schon 2 x geschafft, das der Speicherbedarf konstant bleibt - steigt zwar zwischenzeitlich an, fällt dann aber immer wieder auf den gleichen Wert zurück. Habe mittlerweile auch schon versucht, alle Strings am Ende der Funktion auf '' zu setzen, hat jedoch auch nichts bewirkt.
edit: Habe meine Anwendung im Taskmanager beobachtet und zusätzliche Informationen angezeigt - da habe ich bemerkt, dass meine Anwendung ca. 15000 Seitenfehler pro Minute produziert - was sind Seitenfehler und sind diese problematisch bzw. ein Hinweis auf irgendetwas?
|
|
molotov 
      
Beiträge: 24
|
Verfasst: Do 06.09.07 15:52
Hab nun mein Programm mit einem (relativ alten) Purify gestartet. Dieses wirft folgende Meldungen aus:
[I] Starting Purify'd hmi.exe at 06.09.2007 16:34:08
Instrumented executable: D:\Programme\Rational\Purify\cache\hmi$Purify_D_project_hmi_hmi__v4_HMI 4_@0_@0_@0.exe
Working directory: D:\project\hmi\hmi_v4\HMI 4.0.0.0
Command line arguments: <none>
Process ID: 0x45c
Thread ID: 0x578
[I] Starting main
[E] ABW: Array bounds write in WideCharToMultiByte {277 occurrences}
Writing 65535 bytes to 0x04fc9e7c (65319 bytes at 0x04fc9f54 illegal)
Address 0x04fc9e7c is argument #5 of WideCharToMultiByte
Address 0x04fc9e7c is 100 bytes into a 316 byte block at 0x04fc9e18
Address 0x04fc9e7c points to a HeapAlloc'd block in the default heap
Thread ID: 0x578
Error location
WideCharToMultiByte [KERNEL32.dll]
MsgWaitForMultipleObjects [USER32.dll]
Allocation location
HeapAlloc [KERNEL32.dll]
MsgWaitForMultipleObjects [USER32.dll]
[E] ABW: Array bounds write in WideCharToMultiByte {18 occurrences}
Writing 65535 bytes to 0x04fe402c (65319 bytes at 0x04fe4104 illegal)
Address 0x04fe402c is argument #5 of WideCharToMultiByte
Address 0x04fe402c is 100 bytes into a 316 byte block at 0x04fe3fc8
Address 0x04fe402c points to a HeapAlloc'd block in the default heap
Thread ID: 0x578
Error location
WideCharToMultiByte [KERNEL32.dll]
MsgWaitForMultipleObjects [USER32.dll]
MsgWaitForMultipleObjects [USER32.dll]
Allocation location
HeapAlloc [KERNEL32.dll]
MsgWaitForMultipleObjects [USER32.dll]
MsgWaitForMultipleObjects [USER32.dll]
[E] ABW: Array bounds write in WideCharToMultiByte {10 occurrences}
Writing 65535 bytes to 0x04ffff94 (65319 bytes at 0x0500006c illegal)
Address 0x04ffff94 is argument #5 of WideCharToMultiByte
Address 0x04ffff94 is 100 bytes into a 316 byte block at 0x04ffff30
Address 0x04ffff94 points to a HeapAlloc'd block in the default heap
Thread ID: 0x578
Error location
WideCharToMultiByte [KERNEL32.dll]
SetPropW [USER32.dll]
SetCaretPos [USER32.dll]
SetPropW [USER32.dll]
SetCaretPos [USER32.dll]
MsgWaitForMultipleObjects [USER32.dll]
Allocation location
HeapAlloc [KERNEL32.dll]
SetPropW [USER32.dll]
SetCaretPos [USER32.dll]
SetPropW [USER32.dll]
SetCaretPos [USER32.dll]
MsgWaitForMultipleObjects [USER32.dll]
[I] Summary of all memory leaks... {6954 bytes, 11 blocks}
[W] MLK: Memory leak of 190 bytes from 1 block allocated in ADVAPI32.dll
Distribution of leaked blocks
190 bytes from 1 block of 190 bytes (0x001af998)
Allocation location
RtlAllocateHeap [NTDLL.dll]
??? [ADVAPI32.dll ip=0x77da6a78]
[W] MLK: Memory leak of 52 bytes from 1 block allocated in SetCaretPos [USER32.dll]
Distribution of leaked blocks
52 bytes from 1 block of 52 bytes (0x001bfc30)
Allocation location
HeapAlloc [KERNEL32.dll]
SetCaretPos [USER32.dll]
CreateMenu [USER32.dll]
[W] MLK: Memory leak of 136 bytes from 1 block allocated in calloc [MSVCRT.dll]
Distribution of leaked blocks
136 bytes from 1 block of 136 bytes (0x003d4d60)
Allocation location
calloc [MSVCRT.dll]
[I] MPK: Potential memory leak of 4096 bytes from 1 block allocated in VirtualAlloc [KERNEL32.dll]
Distribution of potentially leaked blocks
4096 bytes from 1 block of 4096 bytes (0x04da0000)
Allocation location
VirtualAlloc [KERNEL32.dll]
[W] MLK: Memory leak of 2452 bytes from 6 blocks allocated in EnumChildWindows [USER32.dll]
Distribution of leaked blocks
1964 bytes from 1 block of 1964 bytes (0x04fb0930)
352 bytes from 1 block of 352 bytes (0x04fb0588)
100 bytes from 1 block of 100 bytes (0x04fb0718)
28 bytes from 1 block of 28 bytes (0x04fb0870)
8 bytes from 2 blocks of 4 bytes (first block: 0x04fb08b0)
Allocation location
LocalAlloc [KERNEL32.dll]
EnumChildWindows [USER32.dll]
GetDlgCtrlID [USER32.dll]
[I] MPK: Potential memory leak of 28 bytes from 1 block allocated in LoadLibraryExA [kernel32.dll]
Distribution of potentially leaked blocks
28 bytes from 1 block of 28 bytes (0x04fc9b80)
Allocation location
HeapAlloc [KERNEL32.dll]
LoadLibraryExA [kernel32.dll]
MsgWaitForMultipleObjects [USER32.dll]
[W] PAR: GetClassInfoExW(0x13e69c) WNDCLASSEX structure size too small... {2 occurrences}
48 bytes required but only 29 bytes specified
Call location
GetClassInfoExW [USER32.dll]
IsValidLocale [kernel32.dll]
[I] Exiting with code 0 (0x00000000)
Process time: 124908 milliseconds
[I] Program terminated at 06.09.2007 16:38:59
[i]
Ich kann damit leider nichts anfangen - Hat von euch jemand eine Ahnung, wo die Speicherlöcher liegen könnten oder ob Purify einen Mist anzeigt!?
|
|
|