1

スレッドから発生するメモリ リークの原因を突き止めようとしています。スレッドは、同期されたイベントを繰り返しトリガーし、スレッドで保護されたオブジェクトを返します。

プロシージャを呼び出すことにより、スレッド内でこのイベントをトリガーします...

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

3 つのプライベート フィールドは、この目的のためにのみ使用されます。イベント トリガーで使用される一時ストレージです。は、Lock と Unlock を必要とする、クリティカル セクションを持つ のTLockBmp単なるラッパーです。TBitmap

次に、Synchronize は次のプロシージャを呼び出します。

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

このイベントは、次の手順で処理されます。

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;

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;

メモリリークメッセージは私が混乱しているものです:

ここに画像の説明を入力

x 3実行時間によって異なりますが、反復回数ではありません。たとえば、スレッドは 20 回の反復を繰り返して表示x 3するか、10 回の反復を繰り返して表示x 7することができますが、繰り返しの回数と比較してリークの数のパターンを見つけることさえできません。これは、すべての反復ではなく、ランダムな瞬間に発生するようです。

そこで、プロシージャーのデバッグに取り掛かりましたResizeBitmapが、それを単独で実行すると、たとえ繰り返し素早く実行しても、メモリー・リークはまったく発生しませんでした。スレッドから繰り返し呼び出すことと関係があるようです。インスタンスの作成/破棄TBitmapがベストプラクティスではないことはわかっていますが、それでも、スレッドから繰り返し呼び出されている場合にのみ、このメモリリークが発生します。実際には例外を発生させない (リソース不足の) 非表示の例外があると想定しているため、メモリ リークとしてトラップされます。

このメモリ リークはどこから発生している可能性がありますか? どうすれば防ぐことができますか?

4

1 に答える 1