一个类实例的生成需要经过对象内存分配、内存初始化、设置对象执行框架三个步骤。
编译器首先调用System._ClassCreate进行对象内存分配、内存初始化的工作。而System._ClassCreate调用TObject类的虚方法NewInstance建立对象的实例空间,继承类通常不需要重载TObject.NewInstance,除非你使用自己的内存管理器,因此缺省是调用TObject.NewInstance。TObject.NewInstance方法将根据编译器在类信息数据中初始化的对象实例尺寸(TObject.InstanceSize),调用系统缺省的MemoryManager.GetMem过程为该对象在堆(Heap)中分配内存,然后调用TObject.InitInstance方法将分配的空间初始化。InitInstance方法首先将对象空间的头4个字节初始化为指向对象类的VMT的指针,然后将其余的空间清零。如果类中还设计了接口,它还要初始化接口表格(Interface Table)。
当对象实例在内存中分配且初始化后,开始设置执行框架。所谓设置执行框架就是执行你在Create方法里真正写的代码。设置执行框架的规矩是先设置基类的框架,然后再设置继承类的,通常用Inherited关键字来实现。
上述工作都做完后,编译器还要调用System._AfterConstruction让你有最后一次机会进行一些事务的处理工作。System._AfterConstruction是调用虚方法AfterConstruction实现的。在TObject中AfterConstruction中只是个Place Holder,你很少需要重载这个方法,重载这个方法通常只是为了与C++ Builder对象模型兼容。
最后,编译器返回对象实例数据的地址指针。
对象释放服务其实就是对象创建服务的逆过程,可以认为对象释放服务就是回收对象在创建过程中分配的资源。
当编译器遇到destructor关键字通常会这样编码:首先调用System._BeforeDestruction,而System._BeforeDestruction继而调用虚方法BeforeDestruction,在TObject中BeforeDestruction中只是个Place Holder,你很少需要重载这个方法,重载这个方法通常只是为了与C++ Builder对象模型兼容。
这之后,编译器调用你在Destroy中真正写的代码,如果当前你在撰写的类是继承链上的一员,不要忘记通过inherited调用父类的析构函数以释放父类分配的资源,但规矩是,先释放当前类的资源,然后再调用父类的,这和对象创建服务中设置对象执行框架的顺序恰好相反。
当前类及继承链中所有类中分配的资源全部释放后,最后执行的就是释放掉对象本身及一些特别数据类型占用的内存空间。编译器调用System._ClassDestroy来完成这件工作。System._ClassDestroy继而调用虚方法FreeInstance,继承类通常不需要重载TObject.FreeInstance,除非你使用自己的内存管理器,因此缺省是调用TObject.FreeInstance。TObject.FreeInstance继而调用TObject.CleanupInstance完成对于字符串数组、宽字符串数组、Variant、未定义类型数组、记录、接口和动态数组这些特别数据类型占用资源的释放[4],最后TObject.FreeInstance调用MemoryManager.FreeMem释放对象本身占用的内存空间。
很有意思的是,对象释放服务与对象创建服务所用方法、函数是一一对应的,是不是有一种很整齐的感觉?
对象创建服务
对象释放服务
System._ClassCreate
System._ClassDestroy
System._AfterConstruction
System._BeforeDestruction
TObject.AfterConstruction(virtual)
TObject.BeforeDestruction(virtual)
TObject.NewInstance(virtual)
TObject.FreeInstance(virtual)
TObject.InitInstance
TObject.CleanupInstance
MemoryManager.GetMem
MemoryManager.FreeMem
还有一点要注意,通常我们不会直接调用 Destroy 来释放对象,而是调用 TObject.Free,它会在释放对象之前检查对象引用是否为 nil。
posted on 2011-02-06 11:36
shaker(太子) 阅读(2113)
评论(0) 编辑 收藏 引用