TStringGrid 的 onDrawColumnCell 事件内存泄漏

Memory Leak on TStringGrid's onDrawColumnCell event

背景:Windows 64 位应用程序,Firemonkey,Delphi XE7

我有大约 10 个 TStringGrid 组件,当单元格中的值不是 'Normal.'

时,所有这些组件都使用相同的 onDrawColumnCell 来更改单元格颜色

我正在使用以下代码,但是如果屏幕上显示红色单元格,则会发生严重的内存泄漏。(如果我将页面滚动到没有显示红色单元格的地方,则不会泄漏内存)。

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; 

有谁知道如何解决内存泄漏问题?

谢谢

你在泄密RowColor。就像您管理的任何资源一样,您需要销毁它。使用标准模式:

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

显然在您的代码中,您将 Obj 替换为 RowColor。我用通用名称编写代码,试图证明这是一种模式。每当您有一个必须管理其生命周期并且其生命周期不会超出创建它的函数的对象时,请应用此模式。

如果您使用的是其中一种移动编译器,那么您的代码就可以了。移动编译器使用 ARC,自动引用计数来管理 class 个实例的生命周期。但桌面编译器并非如此。

如果您安装了 FastMM 的完整版本,您可以获得它来为您提供导致任何泄漏的分配的堆栈跟踪。这通常足以让您找出泄漏的原因。

FWIW 我会更像这样编写代码,只在需要时创建画笔:

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;