Alvin Lin
Alvin Lin

Reputation: 199

Memory Leak on TStringGrid's onDrawColumnCell event

Background: Windows 64-bit application, Firemonkey, Delphi XE7

I have about 10 TStringGrid components and all of which are using the same onDrawColumnCell to change cell colors when the Value in the cells is not 'Normal.'

I am using the following code, but the severe memory leaks happens if the red cells are displayed on the screen.(if I roll the page away where no red cell is shown, no memory is leaked).

procedure TForm.grid_DrawColumnCell(Sender: TObject;
  const Canvas: TCanvas; const Column: TColumn; const Bounds: TRectF;
  const Row: integer; const Value: TValue; const State: TGridDrawStates);
var
  RowColor: TBrush;
begin

  RowColor := TBrush.Create(TBrushKind.Solid, TAlphacolors.Alpha);

  if (Value <> 'Normal') then
    RowColor.Color := TAlphacolors.Red
  else
    RowColor.Color := TAlphacolors.Null;

  Canvas.FillRect(Bounds, 0, 0, [], 1, RowColor);

  { perform default drawing }
  TGrid(Sender).DefaultDrawColumnCell(Canvas, Column, Bounds, Row,
    Value, State);
end; 

Does anyone know how to solve the memory leak problem?

Thanks

Upvotes: 0

Views: 729

Answers (1)

David Heffernan
David Heffernan

Reputation: 612993

You are leaking RowColor. Like any resource that is managed by you, you need to destroy it. Usee the standard pattern:

Obj := TMyClass.Create;
try
  // do stuff with Obj
finally
  Obj.Free;
end;

Obviously in you code you replace Obj with RowColor. I wrote the code with generic names to try to bring out the fact that this is a pattern. Apply this pattern whenever you have an object whose lifetime you have to manage, and whose lifetime does not extend beyond the function in which it is created.

If you were using one of the mobile compilers then your code would be fine. The mobile compilers use ARC, automatic reference counting to manage the lifetime of class instances. But that's not the case with the desktop compilers.

If you installed the full version of FastMM you could get it to give you stack traces for the allocations that led to any leaks. That is usually enough to let you work out the cause of the leak.

FWIW I'd code it more like this, only creating the brush if needed:

var
  RowColor: TBrush;
begin
  if Value <> 'Normal' then
  begin
    RowColor := TBrush.Create(TBrushKind.Solid, TAlphacolors.Red);
    try
      Canvas.FillRect(Bounds, 0, 0, [], 1, RowColor);
    finally
      RowColor.Free;
    end;
  end;
  TGrid(Sender).DefaultDrawColumnCell(Canvas, Column, Bounds, Row,
    Value, State);
end; 

Upvotes: 1

Related Questions