본문 바로가기
delphi

TBitmap32 메모리 누수 해결 방법

by doran365 2024. 8. 2.

TBitmap32는 고성능 그래픽 라이브러리로 많이 사용되지만, 비트맵 기반의 Assign 동작이 스레드 내에서 안전하지 않은 문제가 있습니다. 이로 인해 메모리 누수가 발생하고, 이는 유레카 로그에서도 검출되지 않는 경우가 있습니다. 이 문서에서는 TBitmap32 메모리 누수 문제를 해결하는 방법에 대해 상세히 설명합니다.

TBitmap32 메모리 누수 문제의 원인

TBitmap32에서 메모리 누수가 발생하는 주요 원인은 비트맵 객체(TBitmap)를 할당한 후 해제할 때, 메모리에서 완전히 제거되지 않기 때문입니다. 이는 TBitmap32가 스레드 내에서 비트맵을 안전하게 처리하지 못하는 구조적 문제로부터 발생합니다.

해결책 개요

이 문제를 해결하기 위해서는 GR32.pas 소스를 수정하여 TCustomBitmap32.Assign(Source: TPersistent) 함수 내의 서브 함수 중 Bitmap을 이용한 Assign 부분을 수정해야 합니다. 구체적으로는 SrcBmp.Canvas.Lock과 SrcBmp.Canvas.UnLock을 추가하여 메모리 누수를 방지할 수 있습니다.

GR32.pas 수정 방법

다음은 GR32.pas 파일을 수정하여 메모리 누수를 방지하는 방법에 대한 구체적인 지침입니다.

코드 수정 예제

procedure TCustomBitmap32.Assign(Source: TPersistent);
var
  ...
begin
  ...
  procedure AssignFromBitmap(TargetBitmap: TCustomBitmap32; SrcBmp: TBitmap);
  var
    TransparentColor: TColor32;
    DstP: PColor32;
    I: integer;
    DstColor: TColor32;
  begin
    SrcBmp.Canvas.Lock; //-- Add by niceondal for memory leaks in Thread

    AssignFromGraphicPlain(TargetBitmap, SrcBmp, 0, SrcBmp.PixelFormat <> pf32bit);
    if TargetBitmap.Empty then Exit;

    if SrcBmp.Transparent then
    begin
      TransparentColor := Color32(SrcBmp.TransparentColor) and $00FFFFFF;
      DstP := @TargetBitmap.Bits[0];
      for I := 0 to TargetBitmap.Width * TargetBitmap.Height - 1 do
      begin
        DstColor := DstP^ and $00FFFFFF;
        if DstColor = TransparentColor then
          DstP^ := DstColor;
        Inc(DstP);
      end;
    end;

    if Supports(TargetBitmap.Backend, IFontSupport) then // this is optional
      (TargetBitmap.Backend as IFontSupport).Font.Assign(SrcBmp.Canvas.Font);

    SrcBmp.Canvas.UnLock; //-- Add by niceondal for memory leaks in Thread
  end;
  ...
end;

코드 설명

위의 코드에서 SrcBmp.Canvas.Lock과 SrcBmp.Canvas.UnLock을 추가함으로써 스레드 내에서 비트맵의 메모리 누수를 방지할 수 있습니다. 이는 스레드가 비트맵 객체에 접근할 때 잠금 기능을 추가하여 안전하게 접근할 수 있도록 보장합니다.

상세 설명

SrcBmp.Canvas.Lock의 역할

SrcBmp.Canvas.Lock은 스레드가 비트맵 캔버스에 접근할 때, 다른 스레드가 동일한 리소스에 접근하지 못하도록 잠그는 역할을 합니다. 이를 통해 스레드 간의 충돌을 방지하고 안전한 메모리 관리를 보장합니다.

SrcBmp.Canvas.UnLock의 역할

SrcBmp.Canvas.UnLock은 잠금을 해제하여 다른 스레드가 리소스에 접근할 수 있도록 합니다. 이로 인해 스레드가 작업을 완료한 후에는 다른 스레드가 리소스에 접근할 수 있게 되어, 전체 시스템의 효율성을 높입니다.

추가적인 최적화 방법

IFontSupport 인터페이스 활용

코드에서 IFontSupport 인터페이스를 지원하는 경우, TargetBitmap.Backend의 폰트를 SrcBmp.Canvas.Font로 할당하는 부분도 최적화할 수 있습니다. 이는 폰트 설정을 보다 효율적으로 관리하여 메모리 사용량을 줄이는 데 도움이 됩니다.

if Supports(TargetBitmap.Backend, IFontSupport) then
  (TargetBitmap.Backend as IFontSupport).Font.Assign(SrcBmp.Canvas.Font);

이 부분은 선택 사항이지만, 폰트 설정을 효율적으로 관리하여 메모리 사용을 최적화할 수 있습니다.

결론

TBitmap32의 메모리 누수 문제를 해결하기 위해 GR32.pas 파일을 수정하는 방법을 상세히 설명했습니다. SrcBmp.Canvas.Lock과 SrcBmp.Canvas.UnLock을 추가함으로써 스레드 내에서 안전하게 비트맵 객체를 처리할 수 있습니다. 이를 통해 메모리 누수를 방지하고, 전체 시스템의 안정성과 효율성을 높일 수 있습니다.