分享
 
 
 

对Object Pascal编译器给类对象分配堆内存细节的一种大胆猜测(下)

王朝delphi·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

到了这里,你也许会说,说了半天,都是猜测,或许,OP编译器根本就不会调用那个TObject.NewInstance方法呢!

问得好,再做实验!

还是以上面的那个Tbase类为例,重载TObject.NewInstance方法,如下:

TBase = class(TObject)

x : Integer;

y : Double;

class function NewInstance: TObject; override;

procedure FreeInstance; override;

constructor Create;

end;

{实现}

constructor TBase.Create;

begin

self.x := 2;

self.y := 3.14;

end;

procedure TBase.FreeInstance;

begin

inherited;

ShowMessage(Format('Call %s.FreeInstance!!!',[self.ClassName]));

end;

class function TBase.NewInstance: TObject;

begin

ShowMessage(Format('call %s.NewInstance',[self.ClassName]));

result := inherited NewInstance;

end;

之后进行简单的声明对象:

var

b : Tbase;

begin

b := Tbase.Create; ß在这里设断点!

b.Free;

end;

通过对代码进行跟踪果然在一进入Create就马上调用NewInstance方法。

[说明:一定要重载它才能跟踪到它,在断点处,观察CPU,从反汇编后的代码中可以发现,是先调用一个_ClassCreate,然后才调用NewInstance]

用同样的方法可以分析出b.Free会最终调用到FreeInstance;来释放对象。

我想基本上大的问题已经说请了,Object Pascal为了实现分配堆内存,在你调用构造器的时候:

b := Tbase.Create;

在构造方法内你的代码前,安插了代码调用NewInstance方法,析构时,则在析构函数中你的代码后,调用FreeInstance函数。

那么,现在再来看这种情况:派生

TBase = class(TObject)

x : Integer;

y : Double;

class function NewInstance: TObject; override;

procedure FreeInstance; override;

constructor Create;

end;

TSub = class (TBase)

m : Integer;

n : Double;

constructor Create;

end;

{实现}

constructor TBase.Create;

begin

self.x := 2;

self.y := 3.14;

end;

procedure TBase.FreeInstance;

begin

inherited;

ShowMessage(Format('Call %s.FreeInstance!!!',[self.ClassName]));

end;

class function TBase.NewInstance: TObject;

begin

ShowMessage(Format('call %s.NewInstance',[self.ClassName]));

result := inherited NewInstance;

end;

{ TSub }

constructor TSub.Create;

begin

inherited Create; ß注意这里!

self.m := 4;

self.n := 12.32;

end;

我们已经知道,

var

s : Tsub;

s := Tsub.Create;

时,在进入Tsub.Create内部马上得到了它想要的内存[这里是32字节],那么当:

inherited Create;时,在Tbase.Create内部,还有内存分配的动作吗?我们可以通过三点证明:这里,Tbase.Create只是完成程序员给出的初始化代码,没有进行内存分配的动作。

第一点,ReturnValue := inherited Create;所得到的返回地址和调用Tsub.Create所得到的返回地址相同。

第二点,如果在Tbase.Create内部又分配新的内存,那么

self.x := 2;

self.y := 3.14;

只是针对新的内存操作,而原来的S对象中从TBASE中继承来的X,Y不会变,还是0,但我们发现,S中的X,Y已经改变,所以也可以证明Tbase.Create没有分配新的内存,只是对原有内存中的X,Y进行设置。

第三点,跟踪。这是最简单,最一目了然的方法,看看inherited Create;到底有没有调用NewInstance,实验证明,跟本没有调用。

但是,如果把Tsub.Create中的inherited Create;改为Tbase.Create;情况则大不同了,用上面三种方式发现,它又分配了新的堆内存,这样不但没有达到程序员初始化数据的目的,反而造成了内存泄漏,而这样的BUG是很难找到的。

也就是说,编译器发现如果是通过类来调用构造函数,就会当成是新的类对象进行构造、分配堆内存,如果是在构造器内部inherited Create;只是按常规的处理 类方法 的方式进行处理。我想,对于Anders Hejlsberg[DELPHI设计者],想在编译器中实现这样的功能并非一件难事[实际上,我们通过查看汇编代码也能分析出个中原由,有兴趣者请注意其中的TEST d1,d1指令和其下的跳转指令]。

PS:刚才被网友告知有本书叫《delphi的原子世界》,我很想得到它,如果您手上有它的E-BOOK版,希望您能发给我: coder@vip.sina.com

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有