얼마전 작업한 프로젝트 코드의 메모리 관리 부분을 검토하다가 궁금증이 생겼다.
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;만을 수행하고 넘어가는것이 더 안정적일 수 있다는 것이다.