CLR里的MethodTable,MethodDescChunk,MethodDesc,FixUpPreCode都是什么意思
一:看下面一些概念
1MethodTable
MethodTable可以说在CLR里面无处不在,这个东西主要是作为对象的数据类型存在,主要包含了EEClass
模块地址,类型名称,模块路径等。
2.EEClass
EEclass描述了实例对象和类型里面的函数描述符起始块地址,起始块以MethodDescChunk描述。EEclass
成员变量m_pChunks存放了起始块的地址。
3.MethodDesc
看这个名称就知道,它是函数描述符。主要包含了函数名称,函数所述模块,函数是否被jit编译等属性。
4.FixUpPreCode
从字面理解修理预代码,其实它也是这个功能。就是它描述了托管函数被编译前和编译后的变化。编译前
会调用非托管PrecodeFixupThunk函数,编译后直接跳到编译的结果。
二:它们是如何组织的
MethodTable会通过CLR生成实例化对象。在这个生成的过程中,会初始化EEClass。然后会给MethodDescChunks
以及MethodDesc分配相应的地址,MethodDesc跟MethodDescChunks地址是连接在一起的,类似于MethodDescChunks
->MethodDes(1)->MehtodDesc(2)->MethodDesc(3)...... 这种形式。下面就是把MethodDescChunks当MethodDesc分配
完成的时候,会遍历MethodDesc,没遍历一个,就会出初始化一个FixUpPreCode结构体。用以描述函数没被编译之前
的状态。他们的关联方式如下图所示:

三:CLR是如何被运行出来的
作为一个.Net 程式核心部分,这一块是一个重点也是一个难点
主要的步骤有以下几步:
1.CLR会加载当前项目bin/debug/文件夹下面的【目名称.ConsoleApp15.runtimeconfig.json】的这个文件,以读取runtime 的配置
2.CLR 会获取当前runtime运行时的指针
3.通过runtime运行时指针函数,传递进去需要加载的模块,类名称,以及函数名称,获取到需要调用的函数指针
4.获取到函数指针之后,就可以释放掉上面运行步骤所占用的内存
5.调用获取到的函数指针调用函数,比如Main函数,这个是程式入口。
到了这一步不多说了,因为所有的.net程序都是从Main函数开始的。这样流程就会被C#代码所接管。
四:代码是如何构造的
由于CLR代码长达几十万行甚至几百万行,所以无法一一展示。
这里取一部分看看是如何执行的
1.MethodTable的构建过程(MethodTablebuilder.cpp 12163行)
MethodTableBuilder builder(
NULL,
pClass,
&GetThread()->m_MarshalAlloc,
pamTracker); pMT = builder.BuildMethodTableThrowing(
pAllocator,
pLoaderModule,
pModule,
cl,
pInterfaceBuildInfo,
pLayoutRawFieldInfos,
pParentMethodTable,
&genericsInfo,
parentInst,
(WORD)cInterfaces); END_SO_INTOLERANT_CODE;
RETURN(TypeHandle(pMT));
2.EEclass构建过程(methodtablebuilder.cpp 11957行)
EEClass * pClass = MethodTableBuilder::CreateClass(
pModule,
cl,
fHasLayout,
fIsDelegate,
fIsEnum,
&genericsInfo,
pAllocator,
pamTracker);
3.MethodDescchunks和MethodDesc的构建过程是在buildmethodtablethrowing函数里面调用 AllocAndInitMethodDescs();,先看看 AllocAndInitMethodDescs();函数(methodtablebuilder.cpp 1666行)
VOID MethodTableBuilder::AllocAndInitMethodDescs()
{
STANDARD_VM_CONTRACT;
if (sizeOfMethodDescs != 0)
{
AllocAndInitMethodDescChunk(startIndex, NumDeclaredMethods() - startIndex, sizeOfMethodDescs);
}
}
4.继续看 AllocAndInitMethodDescChunk函数(methodtablebuilder.cpp 6836行),很明显看到了里面构建了methoddescchunks和methoddesc。
VOID MethodTableBuilder::AllocAndInitMethodDescChunk(COUNT_T startIndex, COUNT_T count, SIZE_T sizeOfMethodDescs)
{
CONTRACTL {
STANDARD_VM_CHECK;
PRECONDITION(sizeOfMethodDescs <= MethodDescChunk::MaxSizeOfMethodDescs);
} CONTRACTL_END; void * pMem = GetMemTracker()->Track(
GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(TADDR) + sizeof(MethodDescChunk) + sizeOfMethodDescs))); // Skip pointer to temporary entrypoints
MethodDescChunk * pChunk = (MethodDescChunk *)((BYTE*)pMem + sizeof(TADDR)); COUNT_T methodDescCount = 0; SIZE_T offset = sizeof(MethodDescChunk); #ifdef _PREFAST_
#pragma warning(push)
#pragma warning(disable:22019) // Suppress PREFast warning about integer underflow
#endif // _PREFAST_
for (COUNT_T i = 0; i < count; i++)
#ifdef _PREFAST_
#pragma warning(pop)
#endif // _PREFAST_ {
bmtMDMethod * pMDMethod = (*bmtMethod)[static_cast<SLOT_INDEX>(startIndex + i)]; MethodDesc * pMD = (MethodDesc *)((BYTE *)pChunk + offset); pMD->SetChunkIndex(pChunk); InitNewMethodDesc(pMDMethod, pMD); #ifdef _PREFAST_
#pragma warning(push)
#pragma warning(disable:22018) // Suppress PREFast warning about integer underflow
#endif // _PREFAST_
offset += pMD->SizeOf();
#ifdef _PREFAST_
#pragma warning(pop)
#endif // _PREFAST_ methodDescCount++; // If we're a value class, we want to create duplicate slots
// and MethodDescs for all methods in the vtable
// section (i.e. not non-virtual instance methods or statics).
// In the name of uniformity it would be much nicer
// if we created _all_ value class BoxedEntryPointStubs at this point.
// However, non-virtual instance methods only require unboxing
// stubs in the rare case that we create a delegate to such a
// method, and thus it would be inefficient to create them on
// loading: after all typical structs will have many non-virtual
// instance methods.
//
// Unboxing stubs for non-virtual instance methods are created
// in code:MethodDesc::FindOrCreateAssociatedMethodDesc. if (NeedsTightlyBoundUnboxingStub(pMDMethod))
{
MethodDesc * pUnboxedMD = (MethodDesc *)((BYTE *)pChunk + offset); //////////////////////////////////
// Initialize the new MethodDesc // <NICE> memcpy operations on data structures like MethodDescs are extremely fragile
// and should not be used. We should go to the effort of having proper constructors
// in the MethodDesc class. </NICE> memcpy(pUnboxedMD, pMD, pMD->SizeOf()); // Reset the chunk index
pUnboxedMD->SetChunkIndex(pChunk); if (bmtGenerics->GetNumGenericArgs() == 0) {
pUnboxedMD->SetHasNonVtableSlot();
} //////////////////////////////////////////////////////////
// Modify the original MethodDesc to be an unboxing stub pMD->SetIsUnboxingStub(); ////////////////////////////////////////////////////////////////////
// Add the new MethodDesc to the non-virtual portion of the vtable if (!bmtVT->AddUnboxedMethod(pMDMethod))
BuildMethodTableThrowException(IDS_CLASSLOAD_TOO_MANY_METHODS); pUnboxedMD->SetSlot(pMDMethod->GetUnboxedSlotIndex());
pMDMethod->SetUnboxedMethodDesc(pUnboxedMD); offset += pUnboxedMD->SizeOf();
methodDescCount++;
}
}
_ASSERTE(offset == sizeof(MethodDescChunk) + sizeOfMethodDescs); pChunk->SetSizeAndCount((ULONG)sizeOfMethodDescs, methodDescCount); GetHalfBakedClass()->AddChunk(pChunk);
}
5.关于构建fixupprecode (methodtablebuilder.cpp 10497行)
{
for (MethodDescChunk *pChunk = GetHalfBakedClass()->GetChunks(); pChunk != NULL; pChunk = pChunk->GetNextChunk())
{
// Make sure that temporary entrypoints are create for methods. NGEN uses temporary
// entrypoints as surrogate keys for precodes.
pChunk->EnsureTemporaryEntryPointsCreated(GetLoaderAllocator(), GetMemTracker());
}
}
CLR里的MethodTable,MethodDescChunk,MethodDesc,FixUpPreCode都是什么意思的更多相关文章
- Excel2010表格里设置每页打印时都有表头
在打印Excel表格时常常会出现如果存在多页打印时,往往从第二页开始就会出现没有表头的情况,导致到后面都不清楚对应的是哪个数据,查看时也很麻烦,下面就将为大家介绍如何在Excel表格里设置每页打印时都 ...
- Java 里 如何使用Base64,网上都是废物的说法
百度搜索Java里如何使用Base64,结果很多文章都是让引用第三方Jar包,我靠我想了一下 他妈的Java里连这个都不提供,就直接忽略里那些废物的文章.继续搜索,算是找到答案: Java8以后 官方 ...
- Poseidon 系统是一个日志搜索平台——认证看链接ppt,本质是索引的倒排列表和原始日志数据都存在HDFS,而文档和倒排的元数据都在NOSQL里,同时针对单个filed都使用了独立索引,使用MR来索引和搜索
Poseidon 系统是一个日志搜索平台,可以在百万亿条.100PB 大小的日志数据中快速分析和检索.360 公司是一个安全公司,在追踪 APT(高级持续威胁)事件,经常需要在海量的历史日志数据中检索 ...
- 为什么mvc里面的ModelState.IsValid一只都是true
http://zhidao.baidu.com/link?url=H69JQBpF8vbJEOUUc1RCjRZZ05gSGn6PiPL740aGgR3qIfFTT__pt4KgEg7O47lReYR ...
- 关于微信里wx.getUserInfo获取用户信息都是拼音的转成中文方法
加一个参数:lang:"zh_CN" 就可以了 1. 加在js里面 wx.getUserInfo({ lang:"zh_CN", success: func ...
- 用Notepad++在文本文件里快速在每行头尾都加上指定的内容(转载)
- 揭示同步块索引(上):从lock开始
转自:http://www.cnblogs.com/yuyijq/archive/2009/03/13/1410071.html 大家都知道引用类型对象除实例字段的开销外,还有两个字段的开销:类型指针 ...
- VS工程里的文件都是啥?如何打包? 2015-03-04
打完补充:以下内容全部是我一家之言,只是愿意分享,内容如有不妥还请见谅. ====================================================== 刚才接收了一份代 ...
- m个苹果放在n个筐里,每个筐至少一个,所有的筐都一样,有多少种放法
package com.study; import java.io.BufferedReader; import java.io.IOException; import java.io.InputSt ...
随机推荐
- C++ primer plus读书笔记——第7章 函数——C++的编程模块
第7章 函数--C++的编程模块 1. 函数的返回类型不能是数组,但可以是其他任何一种类型,甚至可以是结构和对象.有趣的是,C++函数不能直接返回数组,但可以将数组作为结构或对象的组成部分来返回. 2 ...
- Spring事务明明开启了,为什么没起作用???
一.事务的特性(ACID) 1.原子性(Atomicity):事务是一个原子操作,由一系列动作组成.事务的原子性确保动作要么全部完成,要么完全不起作用. 2.一致性(Consistency):执行事务 ...
- log日志重复输出问题(没弄明白原因)
在别的模块调用定义好的函数 输出的日志出现第一次输出输出一条,第二次输出输出两条...的情况 最后在定义函数处remove了句柄 引用了https://blog.csdn.net/huilan_sam ...
- [Java] 数据分析 -- NoSQL数据库
MongoDB概念:与关系型数据库对应 database(数据库):数据库 collection(集合):表 document(文档):行 field(域):列/字段 注意事项 文档是一组键值(key ...
- [刷题] 220 Contains Duplicate III
要求 给出整型数组nums和整数k,是否存在索引i和j 使得nums[i]和nums[j]之差不超过t,且i和j之差不超过k 思路 建立k个元素的有序查找表 每次有新元素加入,寻找查找表中大于 num ...
- 【转载】Linux命令-自动挂载文件/etc/fstab功能详解[转]
博客园 首页 新随笔 联系 订阅 管理 随笔 - 322 文章 - 0 评论 - 19 Linux命令-自动挂载文件/etc/fstab功能详解[转] 一./etc/fstab文件的作用 ...
- Docker——Tomcat JVM 内存配置
前言 安装再docker中的tomcat,在下载大文件或者某些情况下,会出现tomcat的内存溢出等情况,所以需要配置tomcat的内存大小,docker中的tomcat内存大小配置有四种方式. 一. ...
- gitbook安装使用教程
以下是gitbook的简略安装使用过程,可以参考一下.后续有时间我再回头修改完善实验目的:安装gitbook后,将相关的文件发布到gitlab上安装node.js在cmd下执行安装npm instal ...
- 四大浏览器JavaScript性能/硬件加速测试
四大浏览器JavaScript性能/硬件加速测试 出处:快科技 2010-09-19 10:52:59 人气: 27925 次 作者:萧萧 编辑:萧萧[爆料] 评论(42) 收藏文章 新 ...
- 程序"三高"解决方案
0. 程序三高 1. 缓存 2. 预处理和延后处理 3. 池化 3.1 内存池 3.2 线程池 3.3 连接池 4. 异步(回调) 5. 消息队列 5.1 服务解耦 5.2 异步处理 5.3 流量削峰 ...