来自线程的同步事件 - 内存泄漏

Jer*_*dge 1 delphi graphics events multithreading memory-leaks

我试图找到来自线程的内存泄漏源.该线程重复触发同步事件,返回一个受线程保护的对象.

我通过调用一个过程在线程中触发此事件...

procedure TDeskMonThread.DoOnImage(const ID: Integer; const R: TRect;
  ABmp: TLockBmp);
begin
  FSyncOnImageID:= ID;
  FSyncOnImageRect:= R;
  FSyncOnImageBmp:= ABmp;
  Synchronize(SYNC_OnImage);
end;
Run Code Online (Sandbox Code Playgroud)

3个私有字段仅用于此目的 - 临时存储在事件触发器中使用.TLockBmp只是一个TBitmap包含临界区的包装器,需要锁定和解锁.

然后,Synchronize调用此过程:

procedure TDeskMonThread.SYNC_OnImage;
begin
  if Assigned(FOnImage) then //trigger event
    FOnImage(FSyncOnImageID, FSyncOnImageRect, FSyncOnImageBmp);
end;
Run Code Online (Sandbox Code Playgroud)

此事件由此过程处理:

procedure TfrmMain.ThreadOnImage(const ID: Integer; const R: TRect;
  ABmp: TLockBmp);
var
  B: TBitmap;
begin
  if ID = FCurMon then begin //Only draw if it's the current monitor
    B:= ABmp.Lock;
    try
      FBmp.Assign(B); //Copy bitmap over
    finally
      ABmp.Unlock; //Hurry and unlock so thread can continue its work
    end;
    ResizeBitmap(FBmp, pbView.ClientWidth, pbView.ClientHeight, clBlack);
    pbView.Canvas.Draw(0, 0, FBmp); //Draw to canvas
  end;
end;
Run Code Online (Sandbox Code Playgroud)

现在我把它缩小到了,ResizeBitmap因为当我注释掉那行代码时,我没有得到内存泄漏.这是程序:

procedure ResizeBitmap(Bitmap: TBitmap; Width, Height: Integer; Background: TColor);
var
  R: TRect;
  B: TBitmap;
  X, Y: Integer;
begin
  if assigned(Bitmap) then begin
    B:= TBitmap.Create;
    try
      if Bitmap.Width > Bitmap.Height then begin
        R.Right:= Width;
        R.Bottom:= ((Width * Bitmap.Height) div Bitmap.Width);
        X:= 0;
        Y:= (Height div 2) - (R.Bottom div 2);
      end else begin
        R.Right:= ((Height * Bitmap.Width) div Bitmap.Height);
        R.Bottom:= Height;
        X:= (Width div 2) - (R.Right div 2);
        Y:= 0;
      end;
      R.Left:= 0;
      R.Top:= 0;
      B.PixelFormat:= Bitmap.PixelFormat;
      B.Width:= Width;
      B.Height:= Height;
      B.Canvas.Brush.Color:= Background;
      B.Canvas.FillRect(B.Canvas.ClipRect);
      B.Canvas.StretchDraw(R, Bitmap);
      Bitmap.Width:= Width;
      Bitmap.Height:= Height;
      Bitmap.Canvas.Brush.Color:= Background;
      Bitmap.Canvas.FillRect(Bitmap.Canvas.ClipRect);
      Bitmap.Canvas.Draw(X, Y, B);
    finally
      B.Free;
    end;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

内存泄漏消息让我感到困惑:

在此输入图像描述

x 3取决于它运行的时间长短,但不是迭代次数.例如,线程可以重复20次迭代并显示x 3或可以重复10次迭代并显示x 7但是我甚至找不到与多少次迭代相比有多少次泄漏的模式.这似乎发生在随机时刻,而不是每次迭代.

所以我开始调试ResizeBitmap程序,但是当我自己运行它时,即使反复且快速地运行它,我也从未得到任何内存泄漏.这似乎与从线程重复调用它有关.我知道它正在创建/销毁一个TBitmap可能不是最佳实践的实例,但是,当它从线程中重复调用时,我只会得到这个内存泄漏.我假设有一个隐藏的异常(资源不足)从来没有实际引发异常 - 因此被困在内存泄漏中.

这个内存泄漏可能来自哪里?我该怎样预防呢?

Mas*_*ler 5

EOutOfResources没有自己的构造函数,所以尝试在各种构造函数中放置条件断点,这样Exception只会触发self.ClassType = EOutOfResources.然后,您将找到创建异常对象的点,并且您应该能够使用堆栈跟踪来确定从该点开始的内容.

此外,如果使用FullDebugMode,泄漏检查通常会变得更加容易.您需要从SourceForge下载完整版的FastMM4,并使用FullDebugMode重建您的项目并启用日志记录.然后,您将获得一个文件,其中包含有关内存泄漏的详细调试信息,而不仅仅是内存泄漏对话框,包括创建时的堆栈跟踪.