一个网站的建设需要哪些流程图,建设网站技术要求,佛山优秀网站建设,网站如何做ICP备案.Net程序员们每天都在和Object在打交道如果你问一个.Net程序员什么是Object#xff0c;他可能会信誓旦旦的告诉你Object还不简单吗#xff0c;就是所有类型的基类这个答案是对的#xff0c;但是不足以说明Object真正是什么 在这篇文章我们将会通过阅读CoreCLR的… .Net程序员们每天都在和Object在打交道如果你问一个.Net程序员什么是Object他可能会信誓旦旦的告诉你Object还不简单吗就是所有类型的基类这个答案是对的但是不足以说明Object真正是什么 在这篇文章我们将会通过阅读CoreCLR的源代码了解Object在内存中的结构和实际到内存中瞧瞧Object Object在内存中的结构 为了便于理解后面的内容我先用一张图说明Object在内存中的结构 .Net中的Object包含了这三个部分 指向头部的指针指向类型信息的指针字段内容 微软有一张更全的图说明的是.Net Framework的结构但是基本和.Net Core一样) frameborder0 scrollingno styleborder-width: initial; border-style: none; width: 550px; height: 589px; Object的源代码解析 Object的定义(摘要)源代码: https://github.com/dotnet/coreclr/blob/master/src/vm/object.h class Object
{PTR_MethodTable m_pMethTab;
} PTR_MethodTable的定义DPTR是一个指针的包装类你可以先理解为MethodTable*的等价源代码: https://github.com/dotnet/coreclr/blob/master/src/vm/common.h typedef DPTR(class MethodTable) PTR_MethodTable; 在Object的定义中我们只看到了一个成员这个成员就是指向类型信息的指针那其他两个部分呢 这是获取指向头部的指针的函数我们可以看到这个指针刚好放在了Object的前面 PTR_ObjHeader GetHeader(){LIMITED_METHOD_DAC_CONTRACT; return dac_castPTR_ObjHeader(this) - 1;
} 这是获取字段内容的函数我们可以看到字段内容刚好放在了Object的后面 PTR_BYTE GetData(void){LIMITED_METHOD_CONTRACT;SUPPORTS_DAC; return dac_castPTR_BYTE(this) sizeof(Object);
} 我们可以看到Object中虽然只定义了指向类型信息的指针但运行时候前面会带指向头部的指针并且后面会带字段内容Object在内存中拥有不定的长度并且起始地址是分配到的内存地址一个指针的大小Object结构比较特殊所以这个对象的生成也需要特殊的处理关于Object的生成我将在后面的篇幅中介绍 Object中定义的m_pMethTab还保存了额外的信息因为这是一个指针值所以总会以4或者8对齐这样最后两个bit会总是为0.Net利用了这两个闲置的bit分别用于保存GC Pinned和GC Marking关于这里我也将在后面的篇幅中介绍 ObjHeader的源代码解析 ObjHeader的定义(摘要)源代码: https://github.com/dotnet/coreclr/blob/master/src/vm/syncblk.h class ObjHeader
{// !!! Notice: m_SyncBlockValue *MUST* be the last field in ObjHeader.#ifdef _WIN64DWORD m_alignpad;#endif // _WIN64VolatileDWORD m_SyncBlockValue; // the Index and the Bits} m_alignpad是用于对齐的让m_SyncBlockValue在后面4位值应该为0m_SyncBlockValue的前6位是标记后面26位是对应的SyncBlock在SyncBlockCache中的索引SyncBlock的作用简单的来说就是用于线程同步的例如下面的代码会用到SyncBlock var obj new object();lock (obj) { } ObjHeader只包含了SyncBlock所以你可以看到有的讲解Object结构的文章中会用SyncBlock代替ObjHeader关于SyncBlock更具体的讲解还可以查看这篇文章 MethodTable的源代码解析 MethodTable的定义(摘要)源代码: https://github.com/dotnet/coreclr/blob/master/src/vm/methodtable.h class MethodTable
{ // Low WORD is component size for array and string types (HasComponentSize() returns true).// Used for flags otherwise.DWORD m_dwFlags; // Base size of instance of this class when allocated on the heapDWORD m_BaseSize;WORD m_wFlags2; // Class token if it fits into 16-bits. If this is (WORD)-1, the class token is stored in the TokenOverflow optional member.WORD m_wToken; // NICE In the normal cases we shouldnt need a full word for each of these /NICEWORD m_wNumVirtuals;WORD m_wNumInterfaces; #ifdef _DEBUGLPCUTF8 debug_m_szClassName;#endif //_DEBUG// Parent PTR_MethodTable if enum_flag_HasIndirectParent is not set. Pointer to indirection cell// if enum_flag_enum_flag_HasIndirectParent is set. The indirection is offset by offsetof(MethodTable, m_pParentMethodTable).// It allows casting helpers to go through parent chain natually. Casting helper do not need need the explicit check// for enum_flag_HasIndirectParentMethodTable.TADDR m_pParentMethodTable;PTR_Module m_pLoaderModule; // LoaderModule. It is equal to the ZapModule in ngened imagesPTR_MethodTableWriteableData m_pWriteableData; union {EEClass * m_pEEClass;TADDR m_pCanonMT;}; // m_pPerInstInfo and m_pInterfaceMap have to be at fixed offsets because of performance sensitive // JITed code and JIT helpers. However, they are frequently not present. The space is used by other// multipurpose slots on first come first served basis if the fixed ones are not present. The other // multipurpose are DispatchMapSlot, NonVirtualSlots, ModuleOverride (see enum_flag_MultipurposeSlotsMask).// The multipurpose slots that do not fit are stored after vtable slots.union{PTR_Dictionary * m_pPerInstInfo;TADDR m_ElementTypeHnd;TADDR m_pMultipurposeSlot1;}; union{InterfaceInfo_t * m_pInterfaceMap;TADDR m_pMultipurposeSlot2;}; // 接下来还有一堆OPTIONAL_MEMBERS这里省去介绍} 这里的字段非常多我将会在后面的篇幅一一讲解这里先说明MethodTable中大概有什么信息 类型的标记例如StaticsMask_Dynamic和StaticsMask_Generics等 (m_dwFlags)如果类型是字符串或数组还会保存每个元素的大小(ComponentSize)例如string是2 int[100]是4 类型需要分配的内存大小 (m_BaseSize)类型信息例如有哪些成员和是否接口等等 (m_pCanonMT) 可以看出这个类型就是用于保存类型信息的反射和动态Cast都需要依赖它 实际查看内存中的Object 对Object的初步分析完了可分析对了吗让我们来实际检查一下内存中Object是什么样子的VisualStudio有反编译和查看内存的功能如下图 这里我定义了MyClass和MyStruct类型先看Console.WriteLine(myClass)这里把第一个参数设置到rcx并且调用Console.WriteLine函数为什么是rcx请看查看参考链接中对fastcall的介绍rbp 0x50 0x1fc8fde110 跳到内存中以后可以看到选中的这8byte是指向对象的指针让我们继续跳到0x1fcad88390 这里我们可以看到MyClass实例的真面目了选中的8byte是指向MethodTable的指针后面分别是指向StringMember的指针和IntMember的内容在这里指向ObjHeader的指针是一个空指针这是正常的微软在代码中有注释This is often zero 这里是StringMember指向的内容分别是指向MethodTable的指针字符串长度和字符串内容 这里是MyClass的MethodTablem_BaseSize是32有兴趣的可以去和MethodTable的成员一一对照这里我就不跟下去了让我们再看下struct是怎么处理的 可以看到只是简单的把值复制到了堆栈空间中rbp是当前frame的堆栈基础地址)让我们再来看下Console.WriteLine对于struct是怎么处理的这里的处理相当有趣 因为需要装箱首先会要来一个箱子箱子放在了rbp30h 把MyStruct中的值复制到了箱子中rax8的8是把值复制到MethodTable之后 复制后接下来把这个箱子传给Console.WriteLine就和MyClass一样了 另外再附一张实际查看ComponentSize的图 彩蛋 看完了.Net中对Object的定义让我们再看下Python中队Object的定义源代码: https://github.com/python/cpython/blob/master/Include/object.h #define PyObject_HEAD PyObject ob_base; // 每个子类都需要把这个放在最开头typedef struct _object {#ifdef Py_TRACE_REFSstruct _object *_ob_next; // Heap中的前一个对象struct _object *_ob_prev; // Heap中的后一个对象#endifPy_ssize_t ob_refcnt; // 引用计数struct _typeobject *ob_type; // 指向类型信息} PyObject; 定义不一样但是作用还是类似的 参考 http://stackoverflow.com/questions/20033353/clr-implementation-of-virtual-method-calls-via-pointer-to-base-classhttp://stackoverflow.com/questions/9808982/clr-implementation-of-virtual-method-calls-to-interface-membershttp://stackoverflow.com/questions/1589669/overhead-of-a-net-arrayhttps://en.wikipedia.org/wiki/X86_calling_conventionshttps://github.com/dotnet/coreclr/blob/master/src/vm/object.inlhttps://github.com/dotnet/coreclr/blob/master/src/vm/object.hhttps://github.com/dotnet/coreclr/blob/master/src/vm/object.cpphttps://github.com/dotnet/coreclr/blob/master/src/vm/syncblk.hhttps://github.com/dotnet/coreclr/blob/master/src/vm/syncblk.cpphttps://github.com/dotnet/coreclr/blob/master/src/vm/methodtable.inlhttps://github.com/dotnet/coreclr/blob/master/src/vm/methodtable.hhttps://github.com/dotnet/coreclr/blob/master/src/vm/methodtable.cpphttps://github.com/dotnet/coreclr/blob/master/src/vm/class.hhttps://github.com/dotnet/coreclr/blob/master/src/inc/daccess.hhttps://github.com/dotnet/coreclr/blob/master/src/debug/daccess/dacfn.cpp 写在最后 因为是刚开始阅读coreclr的代码如果有误请在留言中指出接下来有时间我将会着重阅读和介绍这些内容 Object的生成和销毁Object继承的原理(MethodTable)Object同步的原理(ObjHeader, SyncBlock)GC的工作方式DACCESS 原文地址http://www.cnblogs.com/zkweb/p/6244934.html .NET社区新闻深度好文微信中搜索dotNET跨平台或扫描二维码关注