- 1、本文档共12页,可阅读全部内容。
- 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 5、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 6、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 7、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 8、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
查看更多
对Object Pascal编译器给类对象分配堆内存细节的一种大胆猜测DELPHI,在接触Object Pascal之后,果然领会到了它的整洁和优美,怪不得连《程序设计语言:设计与实现》一书的作者也称赞pascal是“一种极优美的语言”。但在学习过程中遇到了好多问题,特别是对于像我这样由C++转至OP[对Object Pascal的简称]学习的人,由于两种语言风格不同,问号就会更多了。其中,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的《Inside C++ Ojbect Model》,这是一本不可多得的好书,她告诉了你对于C++编译器实现的一些你最迷惑、也是最想关心的细节,但不知DELPHI业界内有没有这样一本书,可以让我清楚的了解到OP编译器具体[具体到每个细节]是如何给一个类对象分配堆内存的 [如果有这样的书,您一定要通知我:coder@] ?
我大胆的做了猜测!
一些小动作都是在Tobject类内部事先已经定义好的!下面让我们来关注一下这几个Tobject类方法(Tobject定义于System.pas):
TObject = class
……
constructor Create;
procedure Free;
class function InitInstance(Instance: Pointer): TObject;
procedure CleanupInstance;
class function InstanceSize: Longint;
class function NewInstance: TObject; virtual;
procedure FreeInstance; virtual;
destructor Destroy; virtual;
end;
从方法的名称上我们能隐约的感觉到:NewInstance和FreeInstance肯定和类对象的构造和析构有些关联!
先来分析一下NewInstance:
class function TObject.NewInstance: TObject;
begin
Result := InitInstance(_GetMem(InstanceSize));
end;
只有一句代码,但却调用了三个其它方法:
1、
class function TObject.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;
constructor Create;
end;
然后分配内存:
b : Tbase ;
?
b := TBase.Create;
我设想分配后的内存布局应是这样的[按C++对象的内存考虑联想的]:
再来看这句:Result := PInteger(Integer(Self)
文档评论(0)