惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Troy Hunt's Blog
Scott Helme
Scott Helme
T
Threat Research - Cisco Blogs
T
Tenable Blog
L
LINUX DO - 热门话题
V
Visual Studio Blog
I
Intezer
Blog — PlanetScale
Blog — PlanetScale
Cisco Talos Blog
Cisco Talos Blog
A
Arctic Wolf
C
Cyber Attacks, Cyber Crime and Cyber Security
F
Fortinet All Blogs
aimingoo的专栏
aimingoo的专栏
Know Your Adversary
Know Your Adversary
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
N
Netflix TechBlog - Medium
SecWiki News
SecWiki News
I
InfoQ
Microsoft Security Blog
Microsoft Security Blog
Project Zero
Project Zero
W
WeLiveSecurity
Microsoft Azure Blog
Microsoft Azure Blog
A
About on SuperTechFans
Recorded Future
Recorded Future
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Vercel News
Vercel News
S
Securelist
Spread Privacy
Spread Privacy
L
LangChain Blog
云风的 BLOG
云风的 BLOG
G
Google Developers Blog
MongoDB | Blog
MongoDB | Blog
Google DeepMind News
Google DeepMind News
Recent Commits to openclaw:main
Recent Commits to openclaw:main
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
CERT Recently Published Vulnerability Notes
罗磊的独立博客
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
The Last Watchdog
The Last Watchdog
Attack and Defense Labs
Attack and Defense Labs
博客园 - 司徒正美
Help Net Security
Help Net Security
L
Lohrmann on Cybersecurity
人人都是产品经理
人人都是产品经理
Forbes - Security
Forbes - Security
Hacker News - Newest:
Hacker News - Newest: "LLM"
PCI Perspectives
PCI Perspectives
博客园 - 【当耐特】
T
Tor Project blog

博客园 - 望天

Web 2.0 网站架构不可或缺的图书 值得收藏的146条民间小偏方 回龙观常用电话 AJAX页面呈现模式选择 AJAX富客户端开发 Ajax框架介绍 EBS架构及实现业务特点 ASP.net 大文件上传 实现 架构师要了解那些?? witLuo介绍 网络负载平衡转发技术简介(转载) 双网卡实现负载均衡技术的实现与原理 AOP方法调用消息截获(之realproxy) Server Application Unavailable 事务处理可选方式 C# 注册COM+组件步骤 在分布式事务中登记时出错 TOrderedList类 TStream类
由TObject原码对类的内存分配
望天 · 2006-11-16 · via 博客园 - 望天

一、分析TObject原码

1.1 1.1 看Delphi之祖TObject究竟干了些什么?

1.1.1 1.1.1 类的实例化

    看System单元,TObject类定义实现了几个非常重要的方法。在这里我们只为了搞清楚类、实例和对象在内存中的分配情况,所以我列出这些相关的方法。如:

 class function InitInstance(Instance: Pointer): TObject;

 class function NewInstance: TObject; virtual;

    这两个方法实现了对类的实例化,其中InitInstance方法完成了在内存中开辟一段空间,并对它进行初始化用于存放一个指向vmt表的指针和零个或者多个指向接口表的指针,该接口是指它实现的接口或者他父类实现的接口。它NewInstance负责调用,其参数为一段内存的指针。而NewInstance是当编译时由_ClassCreate负责调用,即是说在类定义后编译器就对类进行实例化了。以下这段代码表明了这一点:

function _ClassCreate(AClass: TClass; Alloc: Boolean): TObject;
asm
{ -> EAX = pointer to VMT }
{ <- EAX = pointer to instance }
PUSH EDX
PUSH ECX
PUSH EBX
TEST DL,DL
JL @@noAlloc
CALL DWORD PTR [EAX] + VMTOFFSET TObject.NewInstance  ......

    当然类实例的释放,就由下面CleanupInstance和FreeInstance两个函数完成了,同理他们的实现原理大家也可以猜到了,这里就不多说了。

1.1.2 1.1.2 对象的初始化

    由于这部分大家都明白,在TObject中提供了这Create、Destroy和Free方法来完成这方面的工作。

1.1.3 1.1.3 vmt表、实例内存段和对象域关系

    经过对TObject类的分析,我们可以得到如图所示的内存分布图: 

    其中,值得注意的是在类实例化的时候不但存放了本身实现的接口的指针,还存放了他父类所实现的接口指针。由于TObject是所有类的祖先,在整个程序运行过程中,内存对vmt表只存在一份,而对相应的类也只存在一份内实例,但是对多个对象就存在多个对象的数据域了。

二. 二、举例说明

2.1 2.1 Demo代码分析

    在Demo实现这样一段代码,我们利用这样一段代码来检查在类实例的域的大小:

TTest = class(TObject)    // 定义一个类
protected
  function _AddRef: Integer; stdcall;
  function _Release: Integer; stdcall;
  function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
end;
I1 = interface          
['{0012DA37-7EDB-4F91-92DB-ED2EC744F7F4}']
end;
I2 = interface
['{640E732C-2413-4BD7-AC9C-B19AC1C384C7}']
end;
TTest1 = class(TTest, I1)   //定义对I1接口的实现类
end;
TTest2 = class(TTest1, I2)  //定义I2接口的实现类,该类继承与TTest1。
end;

    于是,我们利用下面的函数来得到TTest,TTest1和TTest2类的实例域的大小:

procedure TForm1.Button2Click(Sender: TObject);
begin
  ShowMessage('TTest`s InstanceSize is'+Inttostr(TTest.InstanceSize));
  ShowMessage('TTest1`s InstanceSize is'+Inttostr(TTest1.InstanceSize));
  ShowMessage('TTest2`s InstanceSize is'+Inttostr(TTest2.InstanceSize));
end;

    得到的结果为:

  

    可见他们的结果分别是4、8和12字节,为什么是如此呢?那就让我们再看看上面对内存中Instance域究竟存了什么,在内存的Instance域中存放了一个指向vmt表的指针和一些指向接口的指针。由于TTest类没有实现接口,所以它的Instance域只存放了一个指向类vmt的指针大小为4字节;而TTest1实现了接口I1,所以它的Instance域中存放了一个指向它本身类vmt的指针和一个指向接口的指针,即大小为8字节;由于TTest2是继承于TTest1类来实现I2接口的,所以它的Instance域中多存放一个指向父类接口的指针,即大小为12字节。

2.1.1 2.2 Demo中类的Instance域

 三、总结

    在Delphi中的TObject中它其实做了很多工作,它给以后派生的类定下了规则,其在内存中各种数据域的组织形式。其实,类的实例的初始化和vmt表的构造是用户不可见的,他在编译的时候就在内存分配了。对我们而言,最重要的是对对象的操作。