当前位置: 首页 > news >正文

Object内存核心结构及实现完全剖析(MethodTable、EEClass与MethodDescChunk)

无疑,一个ObjectCLR中的逻辑结构是相当复杂的。
前段时间,写了一篇CLR探索系列:System.Object内存布局模型及实现研究,侧重从System.Object这个基本类的基本内存布局,实现和结构来研究了下。这是远远不够的。今天就从如何存储一个Object中的FieldMethod等信息,这些信息的逻辑组织方式和存储的逻辑结构。

废话不多说,看看就知道了:

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

首先,给一个图:

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />

r_1.JPG
      
  
    这个图,显示了一个
ObjectMethodTableEEClassMethodDescChunk之间的大致关系。至于一个整体的Object的实现的逻辑结构模型图,结构比较复杂,不好画,google了半天也没找到个现成的,就用这个凑合了。

通常,在内存中,对一个instanceref的这个地址,其实是指向这个instanceMethodTable的。这个内容,我在“System.Object这个基本类的基本内存布局,实现和结构”这篇文章里面也有说,具体是如何实现的可以参照那篇文章。

老规矩,截取点MethdTable里面重要的属性,方法和结构体,总共一个MethodTable的实现,就大概2500多行,(太长了?这仅仅是定义部分),只能截取表示如下了:

 

class MethodTable

{   

    // Low WORD is component size for array and string types, zero otherwise

    DWORD           m_wFlags;

 

    // Base size of instance of this class when allocated on the heap

    DWORD           m_BaseSize;

    //Nmuber of Method
   
WORD            m_wNumMethods; 
   
//Number of Vitural Methods

    WORD            m_wNumVirtuals;
   
WORD            m_wNumInterfaces;

       
   
// LoaderModule. It is equal to the ZapModule in ngened images

    PTR_Module      m_pLoaderModule;   

    PTR_MethodTable m_pParentMethodTable;

 

    // This is the way to create a new method table. Don't try calling new directly.

    // Mehtod tables are also created in array.cpp where an EEClass

    // and MethodTable are created in one fell swoop.  I see no rationale basis for

    // such an approach.

    // Even worse almost exactly the same stuff is duplicated in DynamicMethod.cpp.

    // Worse still almost exactly the same stuff is duplicated in generics.cpp.

    //MethodTableNew函数,MethodTalbe不能直接New一个

    static MethodTable * AllocateNewMT(EEClass *pClass,

                                       DWORD dwVtableSlots,

                                       DWORD dwGCSize,

                                       DWORD dwNumInterfaces,

                                       DWORD numGenericArgs,

                                       DWORD dwNumDicts,

                                       DWORD dwNumTypeSlots,

                                       ClassLoader *pClassLoader,

                                       BaseDomain *pDomain,

                                       BOOL isIFace,

                                       BOOL fHasGenericsStaticsInfo,

                                       BOOL fNeedsRemotableMethodInfo,

                                       BOOL fNeedsRemotingVtsInfo,

                                       BOOL fHasThreadOrContextStatics

                                       , AllocMemTracker *pamTracker

        );

 

    // Return total vtable slots : virtual, static, and instance method slots.

    unsigned GetNumMethods()

    {

        LEAF_CONTRACT;

        return m_wNumMethods;

    }

 

    void SetNumMethods(WORD wNumSlots)

    {

        LEAF_CONTRACT;

        m_wNumMethods = wNumSlots;
   
}


       //
使用专门的数据结构来实现对Table中的可写部分的读写。而这些可写的部分,是定义在另外的一个专门的枚举类型的变量中。

PTR_MethodTableWriteableData m_pWriteableData;

//MethodTable类中最重要的一个定义,包涵了对EEClass的引用。

PTR_EEClass     m_pEEClass;

      

       //在寻找所谓的VTable定义的时候,着实费了一番功夫,最后得到一个结论:在sscli2.0中,去掉了m_Vtable[1]的显示定义。更多的是把Vtable当作一个Thunking Layer来在需要的时候操作。

//为此,MethodTalbe的定义中,还专门定义了一个structInteropMethodTableSlotData)来实现模拟就得Vtable结构对COM接口的访问。在需要使用到类似Vtable的时候直接计算某个SlotOffset,并且使用专门的Accessor来进行访问。截取两个方法来说明这点:


    inline PTR_SLOT GetVtable()

    {

        LEAF_CONTRACT;

        return PTR_SLOT((PTR_HOST_TO_TADDR(this) + TADDR(GetVtableOffset())));

    }

 

    static inline DWORD GetVtableOffset()

    {

        LEAF_CONTRACT;

        return (sizeof(MethodTable));

    }

}


      
从下图中也可以很明显的看出MethodTable的结构以及其部分字段的表示的含义:


r_2.JPG

 

       最后给出一个MethodTable中重要的数据结构:


struct ThreadAndContextStaticsBucket

{

    // Offset which points to the TLS storage. Allocated lazily - -1 means no offset allocated yet.

    DWORD m_dwThreadStaticsOffset;

    // Offset which points to the CLS storage. Allocated lazily - -1 means no offset allocated yet.

    DWORD m_dwContextStaticsOffset;

    // Size of TLS fields

    WORD m_wThreadStaticsSize;

    // Size of CLS fields

    WORD m_wContextStaticsSize;

};

typedef DPTR(ThreadAndContextStaticsBucket) PTR_ThreadAndContextStaticsBucket;

 

       在上面的部分属性中,可以看到,一个Object的信息,并不是所有的都保存在MethodTalbe中的。这样分层设计的目的,还是一个字:效率。把一个Object使用的最频繁的部分,保持在MethodTable中,而使用的稍微不频繁的部分,保持到EEClass中,这部分信息,从名字上面就可以看出,主要是包涵了CLR执行引擎所需要的对一个Object的控制信息。也就是如下图所示,各个不同的部分所包涵的内容应用的重点和频率都不同:

      

r_3.JPG

       接着,给出EEClass的一些重要的数据结构:


Class EEClass

{

       //得到这个Object运行的一些基本环境。

       BaseDomain * GetDomain();

    Assembly * GetAssembly();

    Module* GetLoaderModule();

    Module* GetZapModule();

 

       //point out the Module which contains this Object and its EEClass

    PTR_Module m_pModule;

    mdTypeDef m_cl;

       //important property!point to the MethodTable of this Object.

    PTR_MethodTable m_pMethodTable;

 

    // NOTE: Place items that are WORD sized or smaller together,

       //otherwise padding will be used implicitly by the C++ compiler

    WORD m_wCCtorSlot;

    WORD m_wDefaultCtorSlot;

 

    BYTE m_NormType;

       //number of instance Fields

    WORD m_wNumInstanceFields;

       //number of static fields

    WORD m_wNumStaticFields;

    WORD m_wNumHandleStatics;

    WORD m_wNumBoxedStatics;

       //implies the number of Object ref in a instance.

       //GCDesc结构,也就是一个Object实现的时候的头部,Object Header可能会引用到,同时JIT也有可能引用到这个属性。

    WORD m_wNumGCPointerSeries;

 

    DWORD m_cbModuleDynamicID;

    DWORD m_cbNonGCStaticFieldBytes;

    DWORD m_dwNumInstanceFieldBytes;

 

       //这个属性表面了对于一个Object里面的Fields,是在EEClass里面把每个Field对应的FieldDesc类连接在了一起。

FieldDesc *m_pFieldDescList;

 

    DWORD m_dwAttrClass;

    volatile DWORD m_VMFlags;

    SecurityProperties m_SecProps;

       

       //这里定义了MethodDescChunk,从最上面的图可以看到,从一个EEClass中是连接到MethodDescThunk链表上面的。比较重要的一个结构。

    PTR_MethodDescChunk m_pChunks;

}


      
再回头看一下,MethodTablem_VtableVtable in MethodTable),MethodDescChunks这个Chain是如何连接起来的就十分清楚了:

 r_4.JPG

       最后,看看MethodDescChunk这个描述每一个Method的大块头的结构如何,这里,就不在分析一个MethodDescChunk里面究竟是如何实现的了:

o_5.JPG

      

MethodDescChunk的头部是上面的蓝色的部分。Prestub是中间的斜线的部分,而对每个方法的描述的部分,是上图的白色的区域,可以看到,包涵了这个方法的IL代码,SlotNumber,和一些标识位。每一行,是一个DWORD类型。

注意:m_op中,包涵了对这个方法的调用,是call JIT来进行实时编译,还是jump到一个已经编译好了的地方,m_op就是标识这两种不同的操作类型。而m_target里面,则是和m_op对应的内存地址。

 

Ok,写到这里,结合第一次讲System.Object的那篇文章,我想,对一个Object的认识应该有个大体的比较清晰的架构了。

 

最后,做个广告^_^

欢迎志同道合的同志们加入:Share Source CLI核心技术探索团队,这里,有一群对DotNet世界最核心技术充满好奇和执着探索的朋友们,期待你充满智慧的文章和加盟。

 

<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />2008-3-14 19:48:01

相关文章:

  • linux下net-snmp 已经安装,为什么没有 snmpwalk和snmpget
  • [第7天]继续讲,从克隆帐号 讲起
  • 只要讲信义,就有做不完的生意
  • Phoenix OS 最新更新 4/3/2008
  • 什麼是SOAP?
  • 最经典的***入门教材
  • 工控项目开发框架介绍
  • c#获取文件路径
  • 条款二 : 运行时常量(readonly)优于编译时常量(const)
  • SQL Server 2005新功能
  • 是DataGrid的某数字内容列可编辑,并且以NumericStepper组件改变数值。
  • 找工作要做的十件事
  • 什么是数据恢复技术
  • [InnoDB系列] -- SHOW INNODB STATUS 探秘
  • 服务器中的地震仪,MOM2005+SP1部署指南(MOM2005系列之一)
  • co.js - 让异步代码同步化
  • HTTP 简介
  • javascript 哈希表
  • Javascript 原型链
  • java正则表式的使用
  • JS创建对象模式及其对象原型链探究(一):Object模式
  • Logstash 参考指南(目录)
  • Next.js之基础概念(二)
  • Webpack 4 学习01(基础配置)
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 使用docker-compose进行多节点部署
  • 消息队列系列二(IOT中消息队列的应用)
  • Linux权限管理(week1_day5)--技术流ken
  • #define,static,const,三种常量的区别
  • #Linux(make工具和makefile文件以及makefile语法)
  • $ git push -u origin master 推送到远程库出错
  • (¥1011)-(一千零一拾一元整)输出
  • (01)ORB-SLAM2源码无死角解析-(56) 闭环线程→计算Sim3:理论推导(1)求解s,t
  • (2)MFC+openGL单文档框架glFrame
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (笔试题)合法字符串
  • (非本人原创)史记·柴静列传(r4笔记第65天)
  • (附源码)ssm学生管理系统 毕业设计 141543
  • (十二)devops持续集成开发——jenkins的全局工具配置之sonar qube环境安装及配置
  • (四)docker:为mysql和java jar运行环境创建同一网络,容器互联
  • (最优化理论与方法)第二章最优化所需基础知识-第三节:重要凸集举例
  • .NET / MSBuild 扩展编译时什么时候用 BeforeTargets / AfterTargets 什么时候用 DependsOnTargets?
  • .net web项目 调用webService
  • .NET 服务 ServiceController
  • .net(C#)中String.Format如何使用
  • .NET性能优化(文摘)
  • @Data注解的作用
  • @JoinTable会自动删除关联表的数据
  • @staticmethod和@classmethod的作用与区别
  • @SuppressLint(NewApi)和@TargetApi()的区别
  • [2016.7 day.5] T2
  • [23] GaussianAvatars: Photorealistic Head Avatars with Rigged 3D Gaussians
  • [3D基础]理解计算机3D图形学中的坐标系变换
  • [android]-如何在向服务器发送request时附加已保存的cookie数据
  • [codevs 1288] 埃及分数 [IDdfs 迭代加深搜索 ]