| Autor |
Beitrag |
Gausi
      
Beiträge: 8553
Erhaltene Danke: 479
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Mo 03.09.07 10:57
Ich habe seit kurzem ein kleines Memory-Leak. Laut FastMM4 ist es ein String, und wenn ich mir die Log-Datei erstellen lasse, sehe ich, dass der verantwortliche String genau der Projektname ist (ich habe das mal getestet, indem ich den geändert habe). Wenn ich die 8 Bytes vor dem String richtig interpretiere (das sind ja Längenangabe und Referenzzähler, oder?) dann gibt es genau eine Referenz auf diesen String. Ich bin mir aber recht sicher, dass ich den Exenamen/Paramstr(0) ohne den Pfad nirgendwo explizit benutze.
Jemand ne Idee, wo und wie ich die Ursache dafür suchen und beheben kann? Hier mal die Log-Datei, falls jemand damit was anfangen kann:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39:
| A memory block has been leaked. The size is: 44
Stack trace of when this block was allocated (return addresses): 402A57 404C61 405225 40D661 42E01C 4047EC 404853 4073B3 5AC7AE
The block is currently used for an object of class: Unknown
The allocation number is: 146
Current memory dump of 256 bytes starting at pointer address 16A9158: 01 00 00 00 1F 00 00 00 62 6F 61 68 64 61 73 69 73 74 65 69 6E 74 6F 6C 6C 65 73 70 72 6F 67 72 61 6D 6D 2E 65 78 65 00 10 6F 95 FE 80 80 80 80 00 00 00 00 31 92 6A 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 21 0F 00 00 57 2A 40 00 61 4C 40 00 25 52 40 00 61 D6 40 00 CB 91 51 00 E0 B1 55 00 EC 47 40 00 53 48 40 00 B3 73 40 00 77 2A 40 00 D6 4B 40 00 3F 5A 40 00 76 B1 55 00 8C 47 40 00 BA C8 5A 00 33 38 E3 75 BD A9 23 77 00 00 00 00 28 00 00 00 00 00 00 00 90 91 6A 01 80 8C 5E 00 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 6F 6E 95 FE 80 80 80 80 00 00 00 00 D1 92 6A 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1F 0F 00 00 57 2A 40 00 61 4C 40 00 25 52 40 00 61 D6 40 00 CB 91 51 00 . . . . . . . . b o a h d a s i s t e i n t o l l e s p r o g r a m m . e x e . . o • þ € € € € . . . . 1 ’ j . . . . . . . . . . . . . . . . . ! . . . W * @ . a L @ . % R @ . a Ö @ . Ë ‘ Q . à ± U . ì G @ . S H @ . ³ s @ . w * @ . Ö K @ . ? Z @ . v ± U . Œ G @ . º È Z . 3 8 ã u ½ © # w . . . . ( . . . . . . . � ‘ j . € Œ ^ . € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € o n • þ € € € € . . . . Ñ ’ j . . . . . . . . . . . . . . . . . . . . . W * @ . a L @ . % R @ . a Ö @ . Ë ‘ Q .
--------------------------------2007/9/3 11:38:42-------------------------------- This application has leaked memory. The small block leaks are (excluding expected leaks registered by pointer):
37 - 44 bytes: String x 1 |
_________________ We are, we were and will not be.
|
|
Chryzler
      
Beiträge: 1097
Erhaltene Danke: 2
|
Verfasst: Mo 03.09.07 11:50
Kann dir zwar bei dem Problem ned helfen, aber ich frage mich gerade ob ein 44 Byte großes Speicherloch so schlimm ist? Afaik wird der Speicher ja beim Beenden dann sowieso wieder freigegeben, er steht halt nur nicht während der Laufzeit zur Verfügung. Oder hab ich was komplett falsch verstanden? Ich zieh mir mal den Wikipedia-Artikel rein...
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Mo 03.09.07 14:25
Kannst Du für deine EXE von Delphi mal bitte eine Detaillierte Mapfile passend zum Log erzeugen lassen?
Benötigt wird: Detaillierte Mapfile, Mit Debug-DCUs. TD32 oder externe Symbole brauchste nicht.
Da eine Mapfile recht viel über den Source verrät, kannst Du mir ggf. auch die besagte Mapfile (und ggf. den Log, falls sich da was von den Adressen geändert hat) per PN zuschicken.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Gausi 
      
Beiträge: 8553
Erhaltene Danke: 479
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Mo 03.09.07 15:51
Ok, das Thema ist erledigt. BenBE hat mal etwas mit der Mapfile rumgezaubert und den Ursprung des Lecks nach und nach eingegrenzt. Das Leck lag nicht bei mir, sondern in der GnuGetText, die ich zur Internationalisierung einsetze(n möchte). Da wurde im initialization-Teil ein String param0 erstellt (und zwar als param0 := extractfile(paramstr(0))). Habe also ein param0 := ''; in den finalization-Teil eingefügt, und das Problem ist erledigt.
@Chryzler: Klar ist das nicht schlimm (und tatsächlich war das Leck noch ein paar Bytes kleiner), aber sowas kann unter Umständen auch Indiz für andere Probleme sein. Und deswegen möchte is sowas beheben.
_________________ We are, we were and will not be.
Zuletzt bearbeitet von Gausi am Mo 03.09.07 15:55, insgesamt 1-mal bearbeitet
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Mo 03.09.07 15:54
*G* Irgendwie fast das gleiche wie Gausi getippt. Hier aber noch mal mit exakten Debug-Infos, falls jemand auch die Unit benutzen sollte:
Ursache war eine globale Variable ( Param0) in der Unit GnuGettext (Sprachlokalisierung), die in Zeile 2791 ( Initialization-Abschnitt der Unit) wie folgt initialisiert wurde:
Delphi-Quelltext 1:
| Param0 := lowercase(extractfilename(paramstr(0))); |
Eine explizite Zuweisung eines Leerstrings ( Param0 := '';) im Finalization-Abschnitt der Unit behebt das Problem.
Ach ja: Ich hatte zu keiner Zeit den Source des Programmes ... Nur um Neidern vorzubeugen. 
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Martin1966
      
Beiträge: 1068
Win 2000, Win XP
Delphi 7, Delphi 2005
|
Verfasst: Mo 03.09.07 15:56
Gut zu wissen, danke!
Wäre eventuell sinnvoll diesen Bug den Entwicklern von GnuGettext zu melden.
Lg, Martin
_________________ Ein Nutzer der Ecke
|
|
Chryzler
      
Beiträge: 1097
Erhaltene Danke: 2
|
Verfasst: Mo 03.09.07 16:02
Wäre eventuell sinnvoll, uns auch zu zeigen, wie man das aus einer Mapfile rauskriegt. *neidisch* 
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Mo 03.09.07 16:21
Wenn Du das gleich in nem eigenen Programm nutzten willst, solltest Du dir die Datei ODbgMapfile und die referenzierten Units anschauen.
Ich schreib das demnächst aber auch mal als Stand-Alaone, damit man die Mapfile direkt auswerten lassen kann (für gegebene Adressen).
Grobe Anleitung:
1. Fehleradresse suchen --> VPtr_ErrAddr
2. Modul-Basisadresse der EXE auslesen (meist 00400000) --> VPtr_ExeModule
3. Offset des Codesegmentes innerhalb der EXE ermitteln --> VOff_CodeSeg
4. Die relative Adresse der Fehleradresse im Code-Segment bestimmen --> RPtr_ErrAddr := VPtr_ErrAddr - VPtr_ExeModule - VOff_CodeSeg;
5. Suchen nach:
5.1 Dem Unit-Block, dessen Start-Adresse KLEINER GLEICH RPtr_ErrAddr UND dessen Endadresse GRÖSSER als RPtr_ErrAddr ist --> Str_Unitname
5.2 Den globalen Symbol-Eintrag, dessen Startadresse KLEINER GLEICH RPtr_ErrAddr ist. (der Eintrag, mit der größten Adresse, die dieses Kriterium erfüllen) --> Str_GlobalSym
5.3 Das Gleiche für die Zeilennummern wiederholen --> Int_LineNumber
6. Sich über das Ergebnis freuen --> Result := Format('Die besagte Adresse liegt in Unit %s in der Routine %s bei Zeile $d', [Str_Unitname, Str_GlobalSym, Int_LineNumber]);
Kleiner Hinweis bei Stacktraces:
Da bei Stacktraces die Adresse des nächsten Befehls angegeben wird, muss man u.U. eine Zeile weiter oben gucken. Das gilt genau dann, wenn der CALL innerhalb dessen der Fehler auftrat, der letzte ASM-Befehl der Source-Umsetzung einer Zeile war.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Gausi 
      
Beiträge: 8553
Erhaltene Danke: 479
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Mo 03.09.07 16:38
@Fehlermelden: Wenn man den Links zum SVN folgt, dann gibts da eine Version, wo dieser Fehler bereits gefixed ist. Wahrscheinlich wurde das nur noch nicht in die install.exe übernommen.
btw.: man muss diese Zeile auch nicht in den finalization-Teil einpacken - am Ende vom init-Teil geht auch. Die Variable wird nur dort benötigt.
_________________ We are, we were and will not be.
|
|
Chryzler
      
Beiträge: 1097
Erhaltene Danke: 2
|
Verfasst: Mo 03.09.07 17:21
BenBE hat folgendes geschrieben: | Wenn Du das gleich in nem eigenen Programm nutzten willst, solltest Du dir die Datei ODbgMapfile und die referenzierten Units anschauen.
Ich schreib das demnächst aber auch mal als Stand-Alaone, damit man die Mapfile direkt auswerten lassen kann (für gegebene Adressen).
Grobe Anleitung:
1. Fehleradresse suchen --> VPtr_ErrAddr
2. Modul-Basisadresse der EXE auslesen (meist 00400000) --> VPtr_ExeModule
3. Offset des Codesegmentes innerhalb der EXE ermitteln --> VOff_CodeSeg
4. Die relative Adresse der Fehleradresse im Code-Segment bestimmen --> RPtr_ErrAddr := VPtr_ErrAddr - VPtr_ExeModule - VOff_CodeSeg;
5. Suchen nach:
5.1 Dem Unit-Block, dessen Start-Adresse KLEINER GLEICH RPtr_ErrAddr UND dessen Endadresse GRÖSSER als RPtr_ErrAddr ist --> Str_Unitname
5.2 Den globalen Symbol-Eintrag, dessen Startadresse KLEINER GLEICH RPtr_ErrAddr ist. (der Eintrag, mit der größten Adresse, die dieses Kriterium erfüllen) --> Str_GlobalSym
5.3 Das Gleiche für die Zeilennummern wiederholen --> Int_LineNumber
6. Sich über das Ergebnis freuen --> Result := Format('Die besagte Adresse liegt in Unit %s in der Routine %s bei Zeile $d', [Str_Unitname, Str_GlobalSym, Int_LineNumber]);
Kleiner Hinweis bei Stacktraces:
Da bei Stacktraces die Adresse des nächsten Befehls angegeben wird, muss man u.U. eine Zeile weiter oben gucken. Das gilt genau dann, wenn der CALL innerhalb dessen der Fehler auftrat, der letzte ASM-Befehl der Source-Umsetzung einer Zeile war. |
Ähm, danke für die Erklärung erstmal, also das ganze geht mit OllyDbg und dem Plugin so wie ich das verstanden hab? Probier ich später mal aus wenn ich mehr Zeit hab. Na ich meld mich auf jeden Fall nochmal weils nicht geht.. Thx 
|
|
alias5000
      
Beiträge: 2145
WinXP Prof SP2, Ubuntu 9.04
C/C++(Code::Blocks, VS.NET),A51(Keil),Object Pascal(D2005PE, Turbo Delphi Explorer) C# (VS 2008 Express)
|
Verfasst: Mo 03.09.07 18:00
_________________ Programmers never die, they just GOSUB without RETURN
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Mo 03.09.07 20:53
@Chryzler: Nope. Das ganze geht mit reinem Notepad. Einfach die Mapfile mit Notepad öffnen, die Standard-Annahmen VPtr_ExeModule := $00400000; und VOff_CodeSeg := $00001000; treffen und fröhlich drauf los rechnen. Das einzige, was wahrscheinlich sich ändern kann, ist der Modul-Offset im Speicher. Dieser kann (wenn man wirklich will) unter Projekt-->Optionen-->Compiler-->Basisadresse gändert werden. Bei DLLs reichen die Angaben vom Prozess-Explorer (oder dem DebugViewer).
Der Vorteil an dieser Methode ist, dass man sie auf beliebige EXE-Files anwenden kann, zu denen man die Mapfile, aber nicht den Source parat hat, weil dieser z.B. nicht mehr in dieser Form existiert (Kunde meldet Bug in alter Version) oder der Bug so selten reproduziert werden kann (z.B. nur beim Kunde) und man daher schlecht den Source oder Debug-Symbole herausgeben kann.
@alias5000: Wozu muss man Programme starten, wenn man ihre Fehler auch so findet  Im Delphi-Debugger wäre dieser Fehler übrigens so gut wie unauffindbar gewesen, da dieser Teil der Programm-Ausführung nahezu nicht debuggtbar ist.
@Chryzler: Wenn's nicht geht, ich stell demnächst mal noch ne EXE-Version des Parsers online, wo man die Mapfile direkt laden kann und dann seine Adressen automatisch aufgelöst bekommt. Für alle, die zu Rechen- und Suchfaul sind 
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
|