[Delphi] Memory-leak opsporen

Pagina: 1
Acties:

  • jvdmeer
  • Registratie: April 2000
  • Laatst online: 22:57
[algemene vraag]
Ik zit met het probleem dat mijn programma een memoryleak bevat. En die probeer ik op te sporen. Dat laatste lukt niet erg met de standaard debugging optie's van Delphi. Heeft iemand suggestie's hoe ik die het makkelijkst kan vinden.
[/Algemene vraag]

Probleem nader gespecificeerd:
ik heb een programma dat ca. 2,1 miljoen GIFjes moet genereren. Door vele duizenden GIFjes volgens vaste regels te combineren. Hiertoe wordt dus elke keer een GIFje geladen, stukje eruit geknipt en daarna bewaard. Voor het gebruik van GIF binnen Delphi gebruik ik TGifImage van Anders Melander.
Voor de duidelijkheid heb ik een stukje code (compleet ingekort) en bewerkt, zodat er alleen een Form met daarop een TImage en TButton nodig zijn:
Delphi:
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
40
41
42
43
44
45
46
procedure TForm1.Button1Click(Sender: TObject);
var
  BronImg:TRect;
  DoelImg:TRect;
  BronGIF,
  DoelGIF:TGifImage;
  Palette:hPalette;
  TempImg,
  Bitmap:TBitmap;
  Teller:LongInt;
begin
  Palette := 0;
  Bitmap := TBitmap.Create;
  Bitmap.LoadFromFile('Palette.bmp');
  if (Palette = 0) then
    Palette := CopyPalette(Bitmap.Palette);
  Bitmap.Destroy;

  BronGIF:=TGifImage.Create;
  DoelGIF:=TGifImage.Create;
  TempImg := TBitmap.Create;

  TempImg.Width:=100;
  TempImg.Height:=100;

  Bronimg:=Rect(10,  10,100,  100);
  DoelImg:=rect(0,0,90,90);

  for teller:=0 to 10000 do
  begin
    BronGIF.LoadFromFile('Input.gif');
    TempImg.Canvas.CopyRect(DoelImg,BronGif.Bitmap.Canvas,BronImg);
    BronGif.Bitmap.FreeImage;
    Image1.Picture.Bitmap:=ReduceColors(TempImg, rmPalette, dmFloydSteinberg, 0, Palette);
    Image1.Repaint;
    DoelGIF.Assign(Image1.Picture);
    DoelGIF.SaveToFile('Uitvoer.gif');

    Image1.Picture.Bitmap.FreeImage;
    DoelGIF.Bitmap.FreeImage;

    application.ProcessMessages;
  end;
  BronGIF.Free;
  DoelGIF.Free;
end;

Regel 12 t/m 17 zijn nodig om een Palette-handle te krijgen met de juiste kleuren. Is voor dit probleem nauwelijks relevant.
Regel 19 t/m 21 creeert de nodige objecten.
Regel 28 wordt er een willekeurig GIFje geladen
Regel 29 wordt er een stukje uit de eerste tekening naar de 2e gekopieerd.
Regel 30 wordt de 1e tekening ge'free'ed. Pas toegevoegd toen ik de leak had ontdekt.
Regel 31 wordt het gekopieerde stuk in de kleuren van het Palette in Image1 geplaatst.
Regel 33 wordt de GIF met het nieuwe palette geplaatst in een TGifIMage
Regel 34 wordt de GIF weer bewaard.
Regel 36 en 37 worden de afbeeldingen ge'free'ed

Al die "FreeImage" heb ik toegevoegd toen ik de leak had ontdekt. Maar het lekt nog steeds. :(
Hoe kan ik de leak het makkelijkst opsporen.

[2e algemene vraag]
Wat zijn de relaties, verschillen en overeenkomsten tussen TBitmap, TCanvas, TImage en TPicture? Is hier een duidelijke site over? Of een goed boek?
[/2e algemene vraag]

[ Voor 2% gewijzigd door jvdmeer op 11-03-2003 20:45 . Reden: TCanvas toegevoegd aan 2e vraag. ]


  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 23-08 21:27

Creepy

Tactical Espionage Splatterer

Als ik het zo zie geef je je palette niet vrij.

Ook zit er een kleine mem leak in TGifimage voor een bug in Delphi 4. Updates van TGifimage zitten trouwens in de JVCL en TGifimage zelf word niet meer verder ontwikkeld

Met memproof (ben ff de url kwijt) kan je precies zien wat er niet word vrijgegeven.

Edit: en ff kijken of ik dit zelf nog weet. Een TBitmap is een object om een (jawel!) bitmap te kunnen gebruiken, net zoals een TJpeg voor een jpeg en TGifImage voor een gif ;)
TPicture is een algemeen object dat graphics kan bevatten (dus een bitmap, gif, jpeg, icon etc. d.m.v. TBitmap, TGifImage etc.).
TImage is een visueel control voor het tonen van een Tpicture.

[ Voor 86% gewijzigd door Creepy op 11-03-2003 20:12 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • jvdmeer
  • Registratie: April 2000
  • Laatst online: 22:57
Creepy schreef op 11 March 2003 @ 19:55:
Als ik het zo zie geef je je palette niet vrij.
Dat klopt, maar Delphi bevat bijna niets om met een Palette te werken. Vandaar ook deze omweg om een palette te laden. Ik zal het palette proberen vrij te geven, maar die code wordt maar 1 keer uitgevoerd, dus die zal niet in de MB's gaan lopen, wat de memleak helaas wel doet.
Creepy schreef op 11 March 2003 @ 19:55:
Ook zit er een kleine mem leak in TGifimage voor een bug in Delphi 4. Updates van TGifimage zitten trouwens in de JVCL en TGifimage zelf word niet meer verder ontwikkeld
Wat is de JVCL? En ik werk met Delphi 7. Waar vind ik deze updates?
Creepy schreef op 11 March 2003 @ 19:55:
Met memproof (ben ff de url kwijt) kan je precies zien wat er niet word vrijgegeven.
Ga ik op zoeken.
Creepy schreef op 11 March 2003 @ 19:55:
Edit: en ff kijken of ik dit zelf nog weet. Een TBitmap is een object om een (jawel!) bitmap te kunnen gebruiken, net zoals een TJpeg voor een jpeg en TGifImage voor een gif ;)
TPicture is een algemeen object dat graphics kan bevatten (dus een bitmap, gif, jpeg, icon etc. d.m.v. TBitmap, TGifImage etc.).
TImage is een visueel control voor het tonen van een Tpicture.
[/quote]
Als ik je beschrijving zo lees, dan hoeft eigenlijk aan Image1 een TImage te zijn (want die verschijnt op het scherm), en kunnen alle interne bewerkingen van kopiëren enz. met een TBitmap gebeuren. Wat is de functie van TCanvas hierin?

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

MemProof kan je vinden op http://www.automatedqa.com/products/memproof.asp

Enkele opmerkingen over je code:
- Geen .Destroy aanroepen, altijd .Free
- Gebruik try...finally...end;
- TempImage wordt niet vrijgegeven (memory leak)
- FreeImage wordt vanzelf gedaan, niet nodig aan te roepen
- Ben ik niet zeker van, maar de CopyPalette toekenning overschrijft misschien het originele palet van de bitmap (memory leak)

Een TCanvas is het opvervlakte van het plaatje zelf. Je zou hierop kunnen tekenen of van lezen.

Een interresante website over Delphi, Windows en Graphics: http://www.efg2.com/Lab/Library/Delphi/Graphics/index.html

We adore chaos because we like to restore order - M.C. Escher


  • jvdmeer
  • Registratie: April 2000
  • Laatst online: 22:57
Bedankt, ziet er goed uit, ga ik proberen.
LordLarry schreef op 11 maart 2003 @ 20:55:
Enkele opmerkingen over je code:
- Geen .Destroy aanroepen, altijd .Free
- Gebruik try...finally...end;
.destroy gebruik ik (normaal) niet (nu wel, STOM), en de try...finally...end staat in de echte code wel.
LordLarry schreef op 11 maart 2003 @ 20:55:
- TempImage wordt niet vrijgegeven (memory leak)
Dit is maar eenmalig, en kan niet de MB's zijn die ik zie wegvliegen.
LordLarry schreef op 11 maart 2003 @ 20:55:
- FreeImage wordt vanzelf gedaan, niet nodig aan te roepen
Heb ik maar toegevoegd toen ik de mem-leak ontdekte. Stond oorspronkelijk niet in m'n code.
LordLarry schreef op 11 maart 2003 @ 20:55:
- Ben ik niet zeker van, maar de CopyPalette toekenning overschrijft misschien het originele palet van de bitmap (memory leak)
Dit is maar eenmalig, en kan niet de MB's zijn die ik zie wegvliegen.
LordLarry schreef op 11 maart 2003 @ 20:55:
Een TCanvas is het opvervlakte van het plaatje zelf. Je zou hierop kunnen tekenen of van lezen.

Een interresante website over Delphi, Windows en Graphics: http://www.efg2.com/Lab/Library/Delphi/Graphics/index.html
Dit is maar eenmalig, en kan niet de MB's zijn die ik zie wegvliegen.
Bedankt, ga ik bekijken.

En met memory-leak bedoel ik ook echt een memoryleak!:
Afbeeldingslocatie: http://www.home.zonnet.nl/JeroenPetra/memleak.JPG

Dus in ca. 1,5 minuut raak ik 150MB kwijt.

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 23-08 21:27

Creepy

Tactical Espionage Splatterer

jvdmeer schreef op 11 March 2003 @ 20:44:
[...]


Wat is de JVCL? En ik werk met Delphi 7. Waar vind ik deze updates?
Jedi VCL, zie http://www.delphi-jedi.org/ vanaf daar is JVCL wel te vinden.
Melander is dus gestopt met TGifImage en heeft z'n sources aan projecte Jedi gegeven. Het heet ook geen TGifImage meer. De laatste versie die ik heb heeft in elk geval de mem leak voor een workaround van een bug in D4 nog. En de JVCL zit dus een component dat TGifImage in z'n geheel vervangt (en ook comp. met D6 en hoger, iets wat TGifImage eigenlijk niet was, alhoewel het prima werkt)
[...]
Ga ik op zoeken.
Ondertussen heb ik hem ook alweer gevonden ;) http://www.automatedqa.com/downloads/memproof.asp

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


  • jvdmeer
  • Registratie: April 2000
  • Laatst online: 22:57
Creepy schreef op 11 March 2003 @ 23:08:
[...]

Jedi VCL, zie http://www.delphi-jedi.org/ vanaf daar is JVCL wel te vinden.
Site is down for maintenance... moet wachten tot morgen :(

  • jvdmeer
  • Registratie: April 2000
  • Laatst online: 22:57
Met behulp van MemProof gevonden dat het probleem zit in de regel:
Delphi:
1
Image1.Picture.Bitmap:=ReduceColors(TempImg, rmPalette, dmFloydSteinberg, 0, Palette);


Er wordt elke keer opnieuw een nieuwe TBitmap en een nieuw Palette aangemaakt.

Nu heb ik gister zitten experimenteren met allerlei vormen van Free, FreeImage en DeleteObject, maar ik krijg deze Bitmaps niet vrijgegegeven. Weet iemand misschien hoe ik die wel vrij kan geven.

Liefst los ik het nu eerst op m.b.v. TGifImage, en anders ga ik vanavond eens proberen om naar JVCL te kijken. Om TGifImage te veranderen in een ander component.

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 13-08 16:46

curry684

left part of the evil twins

TBitmap.ReleaseHandle?
TBitmap.ReleasePalette?
TBitmap.ReleaseMaskHandle?

ps. handig om te debuggen als je vermoed Windows-resources kwijt te raken: in TaskMgr kun je in het View-menu via Select Columns bekijken hoeveel Handles en GDI-Handles je process in gebruik heeft. Deze zul je in dit geval astronomisch zien toenemen.

En gaf CodeGuard deze leak niet aan? :?

[ Voor 123% gewijzigd door curry684 op 12-03-2003 10:56 ]

Professionele website nodig?


  • jvdmeer
  • Registratie: April 2000
  • Laatst online: 22:57
curry684 schreef op 12 March 2003 @ 10:53:
TBitmap.ReleaseHandle?
TBitmap.ReleasePalette?
TBitmap.ReleaseMaskHandle?
Die had ik ook al geprobeerd, maar ook die bieden geen soelaas. ik zag net op een andere site:
Image.Picture.Assign(NIL)
dus die ga ik vanavond proberen.
curry684 schreef op 12 March 2003 @ 10:53:
ps. handig om te debuggen als je vermoed Windows-resources kwijt te raken: in TaskMgr kun je in het View-menu via Select Columns bekijken hoeveel Handles en GDI-Handles je process in gebruik heeft. Deze zul je in dit geval astronomisch zien toenemen.
Ja, die GDI-Handles lopen inderdaad op, en Memproof gaf al aan dat dat kwam door bovenstaande regel.
curry684 schreef op 12 March 2003 @ 10:53:
En gaf CodeGuard deze leak niet aan? :?
CodeGuard ? Is dit iets binnen Delphi wat ik wel gebruik, maar niet wat het is, of ken ik het niet en gebruik ik het niet? Maar tot op heden, heb ik nog geen last gehad van memleaks. Dus ik kende Memproof en CodeGuard nog niet.

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

CodeGuard zit alleen in BCB, niet in Delphi.

We adore chaos because we like to restore order - M.C. Escher


Verwijderd

jvdmeer schreef op 12 March 2003 @ 09:34:
Delphi:
1
Image1.Picture.Bitmap:=ReduceColors(TempImg, rmPalette, dmFloydSteinberg, 0, Palette);
dit lijkt mij meer logisch:

Delphi:
1
Image1.Picture.Bitmap.assign(ReduceColors(TempImg, rmPalette, dmFloydSteinberg, 0, Palette));

  • jvdmeer
  • Registratie: April 2000
  • Laatst online: 22:57
Zeer interressant staat ge'bookmark'ed.
En ik heb inmiddels ook de oplossing voor mijn probleem:
Eerst een TBitmap declareren (Bitmap in dit voorbeeld) en die als uitgangspunt gebruiken in de lus. Die kan ik gewoon ' Free'en aan het eind van de lus.
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
  for teller:=0 to 10000 do
  begin
    BronGIF.LoadFromFile('Invoer.gif');
    TempImg.Canvas.CopyRect(DoelImg,BronGif.Bitmap.Canvas,BronImg);

    Bitmap:=ReduceColors(TempImg, rmPalette, dmFloydSteinberg, 0, Palette);
    Image1.picture.bitmap.Assign(Bitmap);
    DoelGIF.Assign(Bitmap);
    DoelGIF.SaveToFile('Uitvoer.gif');
    DoelGIF.Bitmap.FreeImage;
    Bitmap.Free;
    application.ProcessMessages;
  end;


Dus ik heb de JEDI-VCL niet meer nodig, alhoewel ik er nog wel naar ga kijken, want hij ziet er zeer interessant uit.
Pagina: 1