一、Object Pascal中对象生存与销毁的秘密
        每个应用程序可以获得的内存空间分为两种:堆(heap)和栈(stack)。
       堆又称为“自由存储区”,其中的内存空间的分配与释放是必须由程序员来控制的。例如,用GetMem函数获取了一定大小的内存空间,则在使用完后,必须调用FreeMem函数将空间释放,否则就会发生所谓的“内存泄漏”。
       栈又称为“自动存储区”,其中的内存空间的分配与释放是由编译器和系统自动完成的,不需要程序员过问。函数调用时按值传递的参数所占空间、函数中的局部变量等,都是在栈中被分配空间的。
       Objecgt Pascal遵循所谓的“引用/值”模型。无论在参数传递还是变量定义中,简单类型(如Integer、Cardinal、char以及record等)被按值传递或使用,其内存空间从栈中分配。而复杂类型(class)则被按引用传递或使用,其内存空间从堆中分配。在Object Pascal中,所有对象(类类型的)都被建立在内存的堆空间上,而非栈上。因此在创建对象时,其构造函数不会被编译器自动调用,也没有C++中所谓的“默认构造函数”。调用构造函数来创建对象以及调用析构函数来消灭对象都是程序员的职责。要创建出一个对象,首先需要分配对象本身所占用的内存空间,然后执行类的构造函数,以初始化各数据成员、申请对象需要的资源或创建其内部包含的子对象。
      与构造函数类似,如果在类中没有特殊的资源需要被释放,也可以不定义析构函数,TObject同样定义了一个空的析构函数。在析构对象的时候,应该调用对象的Free()方法而不是直接调用Destroy()。要销毁一个对象,其顺序与创建对象正好相反。首先是释放对象申请的资源以及销毁内部的子对象,之后是回收对象本身所占的内存空间。永远不要直接调用对象的Destroy(),而应该是Free()。
二、对象所占空间大小
       对象的大小,就是其数据成员所占用的内存空间的总和,其方法(函数)是不占用对象空间的。不过,它不是一个简单的加法,还与编译器的“数据域对齐方式优化”有关 (对象的大小只取决于其拥有的数据成员!!!)。TObject实现了一个InstanceSize()方法,它可以取得对象实例的大小。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
end;
// 自定义的TMyClass类
TMyClass = class
Public
FMember1 : Integer;
FMember2 : Integer;
FMember3 : WORD;
FMember4 : Integer;
Procedure Method();
End;
Form1: TForm1;
implementation
*.dfm}
procedure TForm1.Button1Click(Sender: TObject);
Obj : TMyClass;
begin
Obj := TMyClass.Create();
with memo1.Lines do
begin
Add('对象大小:' + IntToStr(Obj.InstanceSize));
Add('对象所在地址 :' + IntToStr(Integer(Obj)));
Add('FMember1所在地址:' + IntToStr(Integer(@Obj.FMember1)));
Add('FMember2所在地址:' + IntToStr(Integer(@Obj.FMember2)));
Add('FMember3所在地址:' + IntToStr(Integer(@Obj.FMember3)));
Add('FMember4所在地址:' + IntToStr(Integer(@Obj.FMember4)));
end;
Obj.Free();
end;
{ TMyClass }
procedure TMyClass.
begin
//no code
end;
end.
 
Add:
        如果该类是一个派生类的话,,它的对象实例所占内存空间的大小,不但取决于自身的数据成员,还要加上其基类的数据成员(不论是private的,还是public的)。
        原因:每一个派生类的实例对象,内部都包含了一个完整的基类实例对象,这个完整的基类实例对象,就称为“基类子对象”,基类的对象永远小于或者等于派生类的对象。虽然派生类对象无法访问基类子对象中的private的数据,但是,这些数据是的确存在并且占用内存空间的。