얼마전 작업한 프로젝트 코드의 메모리 관리 부분을 검토하다가 궁금증이 생겼다.
TObject.Free
와 Sysutils.FreeAndNil
의 차이점이 무엇일까.
"Free vs FreeAndNil" 키워드로 구글링을 해보니, stackoverflow 질문 글이 가장 먼저 보였다.
Stackoverflow 질문글 : Free or FreeAndNil?
Free
와 FreeAndNil
을 각각 어떤 상황에서 사용해야 하는지, 둘의 차이점은 무엇인지.
라는 질문인데, 추천을 가장 많이 받고 채택도 받은 답변 내용을 짧은 영어 해석과 함께 정리해보았다.
procedure FreeAndNil(var Obj);
var
Temp: TObject;
begin
Temp := TObject(Obj);
Pointer(Obj) := nil;
Temp.Free;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
bm: TBitmap;
begin
bm := TBitmap.Create;
bm.LoadFromFile('C:\Users\User\Desktop\up.bmp');
bm.Free;
if Assigned(bm) then
bm.SaveToFile('C:\Users\User\Desktop\test.bmp')
else
ShowMessage('Cannot save! The bitmap does no longer exist!');
end;
위 코드는 바탕화면에 텅 비어있는 bitmap 파일을 생성할 것이다.
bm
변수를 free
시켜줬기 때문. showmessage
를 출력하지 않고, 파일이 생성되었다.bm
은 여전히 메모리 주소를 point
하고 있는 assigned
상태이기 때문에, Assigned(bm)
의 리턴값은 True
이다.이와 같은 에러를 피하기 위해서, 안전장치로 bm := nil;
을 작성해넣으면 Assigned(bm)
이 false
값을 리턴할 것이다.
그래서 FreeAndNil(bm)
은, 아래 두 줄의 코드를 단축시켜 놓은 것이다.
bm.free;
bm := nil;
결론은 객체가 해제가 되어 있더라도, 변수가 포인팅 하고 있는 메모리 주소까지 해제가 되는것은 아니기 때문에 Assigned()
로 유효성 체크를 하고 넘어가려고 할 때 예상치 못한 Access violation을 마주하게 될 수도 있다는 것이다.
그러면 무조건 FreeAndNil()
을 사용하는것이 좋은것인가? 그건 아닌 것 같다.
왜냐면 FreeAndNil()
자체가 에러가 나는 경우가 종종 있었기 때문인데.. (원인은 잘 모르겠다.)
결국 할당을 해제시킨 변수나 객체를 재사용 할 여지가 있는 경우에는 FreeAndNil()
을 통해 "메모리 할당 해제"와 "초기화(Nil)"를 한번에 수행하는것이 런타임 에러 예방차원에서 좋다는 것이고, 그게 아니라면 Try ~ finally
를 통해 Free;
만을 수행하고 넘어가는것이 더 안정적일 수 있다는 것이다.