보통 도움말에는 Destroy를 직접 호출하지 말고, Free를 호출하라고 되어 있습니다.
그 이유로는 Free를 호출하면 객체가 Nil이 아닌지를 조사하여 Destroy를 호출하여,
안전하다는 것이지요.
하지만, 실제적으로 Free를 호출해도 Nil이 되지는 않습니다. Delphi가 모든 객체에 대한
포인터를 관리하고 있지 않다는 이유에서라고 하더군요. 그래서 객체를 Nil로 만들어주고 싶으면,
FreeAndNil을 호출하라고 말하고 있고요.
그리고, Destroy는 그 후손객체에서 override하여 자신이 Destroy될때, 최적화된 Destroy를 구현하도록,
즉, 자신이 할당한 메모리를 해제하고 부모의 inherited Destroy를 호출하도록 구현되어,
주로 자손클래스에서 override하여 구현된다고 합니다.
그럼, 맨 처음의 부모객체에서의 Destroy에서는 어떤일이 일어날까요?
즉, TObject에서 말입니다.
물론, Object에게 할당했던 메모리를 해제하겠죠?
그래서 문득 궁금하여 델파이의 소스를 찾아보았습니다.
어떤 임의의 한 콘트롤의 VCL 상속관계를 거슬러올라가봤죠.(아래참조)
그런데, TObject의 Destroy에서는 별다른 코드가 없더군요.
단지, TObject의 Free에만 제가 알지 못하는 기계어 코드만 존재하고...-_-;
그럼, 실제로 TObject의 Destroy를 호출하면, 아무일도 안일어나고, TObject의 Free를 호출할때만,
어떤 일들이(아직은 제가 알지 못하는) 일어나네요.
그럼, TObject를 바로 상속받은 객체가 TObject의 Free를 호출하는가 하여 보었지만,
저 아래에서 TObject를 바로 상속받은 TPersistent의 Destroy에서도
inherited Destroy만 호출하고 있습니다.
그럼 , TScrollingWinControl의 객체를 하나 생성하여 Free를 호출했다면, 해당객체가 Nil인지를 조사하고,
Nil이 아니면 그 객체의 destructor를 호출하겠죠. 그러면, 부모클래스를 거쳐가서,
TObject의 Destroy까지 호출될 것입니다. 그런데, TObject의 Destroy엔 아무코드가 없고요.
그런데, 유독 Tobject에서는 Free에서 메모리의 해제등이 일어난다면, 언제 TObject의 Free가 호출될까요?
결국 TObject의 메모리는해제가 안되었다는 얘긴데..
아니면,TObject에 아무런 코드가 없지만, 메모리 해제의 동작이 일어나는 건가요?
조언부탁드립니다...-_-;
1)
destructor TScrollingWinControl.Destroy;
begin
FHorzScrollBar.Free;
FVertScrollBar.Free;
inherited Destroy;
end;
2)
destructor TWinControl.Destroy;
var
I: Integer;
Instance: TControl;
begin
Destroying;
if FDockSite then
begin
FDockSite := False;
RegisterDockSite(Self, False);
end;
FDockManager := nil;
FDockClients.Free;
if Parent <> nil then RemoveFocus(True);
if FHandle <> 0 then DestroyWindowHandle;
I := ControlCount;
while I <> 0 do
begin
Instance := Controls[I - 1];
Remove(Instance);
Instance.Destroy;
I := ControlCount;
end;
FBrush.Free;
if FObjectInstance <> nil then FreeObjectInstance(FObjectInstance);
inherited Destroy;
end;
3)
destructor TControl.Destroy;
begin
Application.ControlDestroyed(Self);
if (FHostDockSite <> nil) and not (csDestroying in FHostDockSite.ComponentState) then
begin
FHostDockSite.Perform(CM_UNDOCKCLIENT, 0, Integer(Self));
SetParent(nil);
Dock(NullDockSite, BoundsRect);
FHostDockSite := nil;
end else
SetParent(nil);
FActionLink.Free;
FActionLink := nil;
FConstraints.Free;
FFont.Free;
StrDispose(FText);
inherited Destroy;
end;
4)
destructor TComponent.Destroy;
var
I: Integer;
begin
Destroying;
if FFreeNotifies <> nil then
begin
for I := FFreeNotifies.Count - 1 downto 0 do
begin
TComponent(FFreeNotifies[I]).Notification(Self, opRemove);
if FFreeNotifies = nil then Break;
end;
FFreeNotifies.Free;
FFreeNotifies := nil;
end;
DestroyComponents;
if FOwner <> nil then FOwner.RemoveComponent(Self);
inherited Destroy;
end;
5)
destructor TPersistent.Destroy;
begin
RemoveFixups(Self);
inherited Destroy;
end;
//여기입니다.!!! Destroy에는 아무코드가 없군요.
6)
destructor TObject.Destroy;
begin
end;
//Free에서 뭔가 코드가 있군요...^^';
procedure TObject.Free;
asm
TEST EAX,EAX
JE @@exit
MOV ECX,[EAX]
MOV DL,1
CALL dword ptr [ECX].vmtDestroy
@@exit:
end;
객체에 대해서 공부한지 오래되어서 기억이 가물가물하지만....
객체의 메모리 해제는 Destroy란 메소드가 하는것이 아니라, destructor이란 예약어가 합니다.
그러니까 Destroy 메소드들에 있는 명령어들을 다 실행한뒤에 이 예약어가 가상메소드테이블(VMT)을 검사해서 객체의 실제 메모리상의 크기만큼 해제하는 거죠....
constructor도 마찬가지의 메카니즘을 가지고 객체를 위한 메모리를 할당합니다.
^^ 항상 즐코하세요...