- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
对ObjectPascal编译器给类对象分配堆内存细节的一种大胆猜测
读过我以前写的文章的网友,都知道我是一个喜欢“刨根问底”、“死钻牛角尖”的家伙。最近由于工作需要转学DELPHI,在接触ObjectPascal之后,果然领会到了它的整洁和优美,怪不得连《程序设计语言:设计与实现》一书的作者也称赞pascal是“一种极优美的语言”。但在学习过程中遇到了好多问题,特别是对于像我这样由C++转至OP[对ObjectPascal的简称]学习的人,由于两种语言风格不同,问号就会更多了。其中,OP和C++语言的一个很大的区别就是:类对象[或称之为类实例]的内存分配机制不同。其中有两方面要说:
一、什么时候分配?
在C++中,定义了对象,那么马上分配其内存,之后调用其构造函数,这个内存可能在堆中,也可能在栈内,也可能在全程数据区内。但OP却截然不同,定义一对象,如:obj:TObject;只是为其分配了4字节的一个指针空间,而真正的对象空间还没有分配,那怎么用?在使用前当然要给对象分配空间,不然就会造成访问内存出错,给对象分配空间的办法也很简单:
obj:=Tobject.Create;
就OK,这个对象空间是分配在堆内的,大家知道,栈内空间可以在使用期过后自动回收,但堆内存需要程序员自己管理,所以在使用完类对象之后,别忘了obj.Free[真正实现析构的是obj.Destroy,但obj.free是一种更安全的方式]。
“什么时候分配”这个问题在OP和C++上的答案确实不同,但还不至于让我“疑惑”。知道了OP类对象是通过调用这样的语句(构造函数):obj:=Tobject.Create;来得到堆内存的,但在这个处理细节上,编译器在内部是如何实现分配堆内存的呢?
请看下一个问题:
二、OP编译器是如何分配的内存?
首先要感谢Lippman的《InsideC++OjbectModel》,这是一本不可多得的好书,她告诉了你对于C++编译器实现的一些你最迷惑、也是最想关心的细节,但不知DELPHI业界内有没有这样一本书,可以让我清楚的了解到OP编译器具体[具体到每个细节]是如何给一个类对象分配堆内存的[如果有这样的书,您一定要通知我:coder@]?
我大胆的做了猜测!
一些小动作都是在Tobject类内部事先已经定义好的!下面让我们来关注一下这几个Tobject类方法(Tobject定义于System.pas):
TObject=class
??
constructorCreate;procedureFree;
classfunctionInitInstance(Instance:Pointer):TObject;procedureCleanupInstance;
classfunctionInstanceSize:Longint;
classfunctionNewInstance:TObject;virtual;procedureFreeInstance;virtual;
destructorDestroy;virtual;end;
从方法的名称上我们能隐约的感觉到:NewInstance和FreeInstance肯定和类对象的构造和析构有些关联!
先来分析一下NewInstance:
classfunctionTObject.NewInstance:TObject;begin
Result:=InitInstance(_GetMem(InstanceSize));end;
只有一句代码,但却调用了三个其它方法:
1、
classfunctionTObject.InstanceSize:Longint;begin
Result:=PInteger(Integer(Self)+vmtInstanceSize)^;end;
这个方法是OP类实现RTTI的一个重要方法,它能返回类对象所需要占用堆内存的大小,注意它并非是类对象所占有内存大小,因为类对象是一指针,那么在32位环境
下,指针永远是4字节!
大家可能对这句代码比较疑惑Result:=PInteger(Integer(Self)+vmtInstanceSize)^;下面我定义一个OP类:
TBase
=
class(TObject)
x
:
Integer;
y
:
Double;
constructorCreate;
end;
然后分配内存:
b:Tbase;
b:=TBase.Create;
我设想分配后的内存布局应是这样的[按C++对象的内存考虑联想的]:
文档评论(0)