Recent

Author Topic: TIcon Memory Leak  (Read 3486 times)

Steve

  • New Member
  • *
  • Posts: 11
TIcon Memory Leak
« on: August 14, 2015, 01:53:42 pm »
Hi,

I am using Lazarus 1.4.2 with FPC 2.6.4 SVN 49524 32-bit on Windows 10 64-bit OS.

I am having an issue with a memory leak when using a TIcon.

Code: [Select]
var
  ico: TIcon;
  bmp: TBitmap;
begin
  ico:= TIcon.Create;
  bmp:= TBitmap.Create;
  bmp.Height:= 50;
  bmp.Width:= 100;
  bmp.Canvas.Brush.Style:= bsSolid;
  bmp.Canvas.Brush.Color:= clBlack;
  bmp.Canvas.Font.Color:= clWhite;
  bmp.Canvas.TextOut(10,10,'Testing');
  PaintBox.Canvas.Draw(10,20, bmp);
  ico.Assign(bmp);
  bmp.Free;
  PaintBox.Canvas.Draw(10,80, ico);
  ico.Free; 


After closing the application heaptrc is reporting 1 unfreed memory blocks and is referencing the ico.Assign(bmp) line.

Does anyone know what I need to do to free the memory? I have tried calling TIcon.Destroy instead of TIcon.Free but that hasn't made any difference.

Note that the code above is a simple example which reproduces the problem. The actual application is getting Windows icons with SHGetFileInfo, hence why I want the icon and not the bitmap.

Thanks
« Last Edit: August 14, 2015, 01:57:32 pm by Steve »

ChrisF

  • Hero Member
  • *****
  • Posts: 542
Re: TIcon Memory Leak
« Reply #1 on: August 15, 2015, 04:17:02 pm »
Possibly a bug in the LLCL, but I'm not sure...

If you assign directly an icon, everything is fine. Like: "ico.Assign(Application.Icon);"

But when a raster image is assigned, a list and one image member are created. Then, the image data are moved from the source to this new image member.

Extract of icon.inc:
Code: [Select]
procedure TCustomIcon.Assign(Source: TPersistent);
...
  if Source is TRasterImage
  then begin
    Clear;

    with TRasterImage(Source) do
      Self.Add(PixelFormat, Height, Width);

    AssignImage(TRasterImage(Source));
...

I've tried to free directly the images (Images[index]) and the list (FSharedImage), but apparently they are not involved in the memory leak (i.e. they are correctly freed by the LCL, IMHO).

I guess, some "intermediate" graphical object might be not freed during this operation. Furthermore, the size of the memory leak is depending of the size of the assigned raster image.


Anyway, I'm not sure to understand your last paragraph. If you don't use a raster image, it seems OK to me.

For instance (when trying to adapt your sample code):
Code: [Select]
uses ..., Windows;

procedure TForm1.Button1Click(Sender: TObject);
const SHGFI_ICON = $000000100;
var
  ico: TIcon;
  MyshFileInfo: SHFILEINFO;
begin
  if SHGetFileInfo(PChar(ParamStr(0)), 0, MyshFileInfo, SizeOf(MyshFileInfo), SHGFI_ICON)=0 then
    begin
      ShowMessage('Error when calling SHGetFileInfo');
      Exit;
    end;
  ico:= TIcon.Create;
  ico.Handle := MyshFileInfo.hIcon;
  PaintBox.Canvas.TextOut(10,60,'Index is '+IntToStr(MyshFileInfo.iIcon));
  PaintBox.Canvas.Draw(10,80, ico);
  ico.Free;
  DestroyIcon(MyshFileInfo.hIcon);    // Free it, if we don't need it any more
end;

I've got no memory leak with this kind of code.

Blaazen

  • Hero Member
  • *****
  • Posts: 3034
  • POKE 54296,15
    • Eye-Candy Controls
Re: TIcon Memory Leak
« Reply #2 on: August 15, 2015, 04:30:05 pm »
I cannot reproduce with trunk (Lazarus 1.5 r49658:49664M FPC 3.1.1 x86_64-linux-qt).

Sorry, I can reproduce (with r. 49672), I forgot to switch HeapTrace on. Also in ico.Assign(); method.
« Last Edit: August 15, 2015, 04:37:56 pm by Blaazen »
Lazarus 2.1.0 r64546 FPC 3.3.1 r40507 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

Steve

  • New Member
  • *
  • Posts: 11
Re: TIcon Memory Leak
« Reply #3 on: August 16, 2015, 03:29:41 am »
Thank you so much for your detailed reply Chris. You have completely solved the problem in my application.

I had been using a TBitmap as an intermediary means of getting the icon from SHGetFileInfo into a TIcon. This was because I didn't know what I was doing and copied some code from an old post. Your reply has shown me how to do it correctly and making that change has stopped the memory leak.

This highlights the fact that I should have actually posted the real code and not an example which was just a side effect of doing something else incorrectly. Anyway, it is really great having access to more experienced and knowledgeable people on this forum! Thanks for all the replies  :)

 

TinyPortal © 2005-2018