(转载)Metadata.NET平台的核心灵魂

July 7th, 2010 jzli Leave a comment Go to comments

网友来信:李老师,您好!我参加过你去年到我们公司做的.NET深度培训,也拜读过你的译作:《.NET框架程序设计(修订版)》和 《Effective C#》,受益匪浅,非常佩服你这样优秀的.NET技术专家。前几天在博客园上的C#大论战,不知道您看过吗?特别是其中一个网友firelong所写的几篇轰动的帖子,对.NET的性能提 出了许多批评。这个话题在我们项目组(大多数都参加过你去年的培训)也引起了很多争论,很想听听李老师对这些观点的看法?……….

本来是以email的形式回复这位朋友的,但是写着写着发现写得长了,最后考虑将其以博文的形式登出。

其实个人无意参与这样的论战,因为很多口水帖、情绪贴. 我简单浏览了一下,发现论战的各方(firelongjeffreyzhao,以及.NET社区众网友),最后都情绪激动了,情绪激 动之下讲的话大多都丢失了技术最扎实、最基本的原理。但是这些文章在口水之外,确实有一些深层次的技术问题暴露出来——有些甚至跨越.NET,而延伸到更 广泛的领域。但是,它们却被口水淹没了,没有好好深入讨论下去,非常可惜。这便是我最后决定写这篇文章的原因。我希望能够对其中被忽视的一些技术问题,做 一些有意义的探讨,与大家共享。

首先我想就《C# 会重蹈覆辙吗?系列之2:反射及元数据的性能问题》一文中的主要技术点来谈谈。这篇文章主要观点如下(并且给了相应的分析):
1. 使用反射会有很高的性能成本
2. 即使不用反射,为支持反射而产生的metadata也有很高的性能成本

因此,作者才得出来在《C 与C++社区混战,C#会重蹈覆辙吗?》一文中“删除反射”的结论。关于反射和metadata带来的性能问题,我想没有人会否认,只是其性能问 题到底有多糟?我后面有空的话也许会另文讨论(firelong文章中有部分含糊其辞)。

本文中,我想讨论的是《C# 会重蹈覆辙吗?系列之2:反射及元数据的性能问题》一文的整个推理过程中的一个基本论点:.NET平台中metadata的目的是为了支持反射。

在这个论点的基础上,文中才有“反射并不常用,为了支持反射所创建的metadata却带来很多性能问题。因此删除反射,也就不需要创建 metadata,这样.NET就不会为此再付出性能损失(就像C、C++那样)”。

很不幸,这个基本论点是对.NET平台的极大误解。换言之,在.NET平台中metadata的存在绝对不仅仅只是支持反射。实际上,支持反射只是 metadata一个很小的用武之地,metadata是整个.NET平台非常核心的基础支撑设施,它在.NET平台中有着广泛的应用,是.NET平台的 灵魂。

为什么这么讲?这要从.NET创建时的整个软件时代背景来谈起,我们才能深刻理解这一点。.NET创建之前,Windows平台的软件技术经历了以 下几个阶段:DDE、OLE、ActiveX/COM。这些技术所努力解决的核心目标是:软件组件的复用性——这是软件开发的核心命题,是软件平台厂商竞逐的焦点。“软件组件的复用性”有以下几个含义:

1. 强调二进制级的复用(黑盒复用),而不是源代码级的复用(白盒复用)。
例如:我想在我的软件中集成PDF阅读器的能力,我不需要找Adobe要PDF阅读器的源代码,而是去找Adobe要一个支持PDF阅读的二进制组件—— 然后通过接口的方式来使用它。
2. 强调多语言创建的组件之间的复用,而不是单一语言创建的组件之间的复用。
例如:我在C++中写一个Email收发组件,可以在VB中直接使用。

DDE、OLE、ActiveX/COM无一不是围绕这个目标。COM是这些技术发展进程中的一个高峰。但是COM技术本身在发展过程中暴露出了很 多问题。Don Box在《Essential .NET》一书的第一章“The CLR as a Better COM”对COM的问题有非常深刻的解剖。

首先,要达致“组件复用”这一目标,必须有合同来规范组件与执行环境、组件与组件之间的各种约定。COM使用的是IDL或TLB作为组件合同,但它 们有几个根深蒂固的缺点:

1. IDL/TLB规范的是物理语义(例如v-table偏移,栈帧,参数,数据结构,对齐等内存细节),且使用的是C++语言的一个子集约定。
2. IDL/TLB规范描述与组件代码本身分离。
3. IDL/TLB规范较为混乱,没有达成业界统一的标准(第三方难以扩展开发)

其中第3点问题是微软对COM没有前后一致的系统规划导致——这一点如果假以时日是可以解决的。但是前面1、2点的问题是COM根深蒂固的问题,导 致了COM组件后期出现的各种难以解决的问题——不同语言实现面向COM的编译很难,因为满足了COM的复用模型,往往要打破该语言本身模型所约定的复 用。同时在一个语言中维护两套编译模型、和复用机制,步履维艰(在C++、VB、Delphi等语言中开发COM组件的痛苦相信很多人深有体会)。

而这个时候,95-98年间名声大噪的Java给了微软相当大的启发。特别是其中的metadata,微软的技术精英发现metadata是最好的 组件合同定义体。Metadata有以下几个非常好的特点(这些正好克服了COM组件描述IDL/TLB的缺点):

1. Metadata描述的是逻辑结构,不涉及任何物理细节(例如v-table偏移,栈帧,参数,数据结构,对齐,方法地址等物理细节,直到在具体平台上加 载、执行时,才被确定,比如IL代码中经常看到的CALL指令后面的 MyClass:MyMethod就是逻辑上的元数据,而不是具体方法的物理地址)
2. Metadata本身与组件代码合并在一个文件中(即程序集),包含了组件依赖,版本等信息
3. Metadata从一开始就经过系统、精心的设计,是CLI业界标准的一部分(便于第三方开发相关应用)

这些特点使得metadata非常适合作为.NET组件与执行环境(CLR)、组件与组件之间(不用语言开发的组件)理想的合同规范。特别是第1 点,“Metadata虚拟的逻辑属性”使得组件合同专注于“逻辑语义层面”,而非“物理实现细节”。简单解释一下:
1. 组件与组件的复用从此集中于“逻辑语义层面”,比如C1的方法M1中调用MyClass的方法MyMethod,用语义表达为:call MyClass:MyMethod。或者C1类继承C2类:用语义表达为:class C1 extends C2。或者调用虚方法:callvirt MyClass:VirtualMethod….
2. 组件与组件的复用不再纠缠于“物理实现细节”,例如:调用某个方法,必须知道它的入口点地址如jmp 0×000688;继承某个类,必须清楚它的字段layout等等,调用虚方法,必须清楚v-table偏移规定…..

那为什么“专注于逻辑语义层面的合同”要优于“专注于物理实现细节的合同”呢?

这就又要回到前面说的“软件组件的复用性”这一目标上来。简单来说,如果要实现“软件组件的复用性(注意二进制、多语言两个属性)”,“专注于物理 实现细节”对于各个语言的编译器厂商,要求太高了,各编译器厂商要协调一个执行体各个方面的物理细节(v-table偏移,栈帧,参数,数据结构,对齐, 方法地址等等…..不一而足)——这么多细节的要求,使得大家极难协调——COM后期的弊端丛生就源于此。

而“专注于逻辑语义层面”来实现组件的复用性,各编译器厂商生成的执行体(即.NET里面的程序集)只需要“用metadata表达逻辑语义上的复 用规范”即可——这对于各编译器厂商需要协调的规范的量级大大减少,实现起来相对容易得多。也不容易在各种细节上出现漏洞——因为大量的物理细节全由 CLR执行时来确定。

综上所述,metadata的根本性的作用是支持基于逻辑语义的组件复用”——这是.NET致力于打造软件开发平台的核心目标。支持反射仅仅是metadata一个很小的衍生功能,而非主要功能。

事实上除了支持“基于逻辑语义的组件复用”这一核心目标外,metadata在.NET平台中还起着其他重要作用(有些是组件复用的延伸需求,比如 JIT与跨平台):

1. Metadata是JIT编译、亦即实现.NET跨平台的基础
说明:IL代码中大量引用着Metadata。在MethodDef元数据表里面存储着一个方法的各种语义信息,许多IL指令就直接内嵌了 Metadata Tokens。没有Metadata,JIT也无法实现。

2. Metadata是.NET支持垃圾收集GC的基础
说明:metadata标记了对象与对象间的引用关系,这是GC遍历对象图(判断对象是否可以收集)的关键依据。没有metadata,GC将不知道 0×000688是一个指针(需要继续遍历)?还是一个整数(不需要继续遍历)?

3. Metadata是描述类型契约、标识、规范等的基本信息
说明:强命名程序集(使用metadata描述)唯一标识了编译器当初编译时的组件,不至于导致运行期仿冒、或者版本偷换(即DLL 地狱问题)

4. Metadata是.NET管理组件安全的基础(运行时类型检查,组件下载)
说明:metadata会告诉CLR执行环境一个组件的安全边界,从而可以管理那些恶意代码。

5. Metadata是.NET管理组件引用关系,加载的基础
说明:metadata会告诉一个组件需要引用哪些组件(哪些版本)?这是组件加载的基础。

从这里大家可以看出来,Metadata是.NET平台实实在在的基石。Metadata之于.NET平台,就像维他命至于生物体一样。换言之,删 除反射,并不能消除metadata。如果要消除metadata,.NET平台的整个设计基础(组件复用,以及上述的其他种种功能)将不复存在。

最后,指出《C# 会重蹈覆辙吗?系列之2:反射及元数据的性能问题》一文中的核心论据错误,并非为了追求驳倒firelong。建议 firelong,jeffreyzhao以及这场辩论的众多技术领域的网友(不管是firelong,jeffreyzhao支持者还是反对者),抛掉 “非要辩个胜负,分个高低”的怪诞氛围,而是来一些扎扎实实的技术说理过程,相信会更有意义——如是,则国内技术社区成长可待!

Metadata是.NET平台的核心灵魂--(转载)的更多相关文章

  1. 2014 Container技术大会:未来Linux Container会是PaaS平台的核心

    不应错过2014 Container技术大会的九大理由. 一.Docker官方人员再次来到北京,首次向中国布道Docker技术.2013年Docker高级软件工程师Jerome Petazzoni,曾 ...

  2. 简要分析武汉一起好P2P平台的核心功能

    写作背景 加入武汉一起好,正式工作40天了,对公司的核心业务有了更多的了解,想梳理下自己对于P2P平台的认识. 武汉一起好,自己运营的yiqihao.com,是用PHP实现的,同时也帮助若干P2P平台 ...

  3. 基于xilinx Zynq UltraScale MPSoC平台的核心板及开发板介绍-米尔科技

    近日,米尔科技推出国内首款基于xilinx Zynq UltraScale+MPSoC 平台的核心板及开发板.其优势主要有:采用16纳米制程,相比Znyq7000系列每瓦性能提升5倍,且单芯片融合4核 ...

  4. C#开发微信公众平台-就这么简单(转载)(附原文链接)

    一直使用的是一百八的诺鸡鸭,没有想去接触看起来风风火火的移动互联网:但因工作需要维护一个微信公众订阅号,考虑以前有做网站的基础,就想着做个简单的微信后台管理:看了官方的开发文档,比狗哥地图的短许多,又 ...

  5. Maven学习总结(四)——Maven核心概念--转载

    一.Maven坐标 1.1.什么是坐标? 在平面几何中坐标(x,y)可以标识平面中唯一的一点. 1.2.Maven坐标主要组成 groupId:组织标识(包名) artifactId:项目名称 ver ...

  6. Maven学习总结(四)——Maven核心概念——转载

    一.Maven坐标 1.1.什么是坐标? 在平面几何中坐标(x,y)可以标识平面中唯一的一点. 1.2.Maven坐标主要组成 groupId:组织标识(包名) artifactId:项目名称 ver ...

  7. SonarQube代码质量管理平台安装与使用--转载

    原文:http://blog.csdn.net/hunterno4/article/details/11687269 Sonar简介 Sonar是一个用于代码质量管理的开源平台,用于管理源代码的质量, ...

  8. Android平台及其架构(部分转载)

    一.Android的系统架构 1.      应用程序 同Android系统一起发布的核心应用程序,如email 客户端,SMS 短消息程序,日历,地图,浏览器,联系人管理程序等. 这些应用程序都是用 ...

  9. windows平台上运行Flink_转载于CSDN

    Flink安装部署-window 本地部署原创冰上浮云 发布于2019-08-17 15:56:06 阅读数 633 收藏分类专栏: flink版权声明:本文为博主原创文章,遵循 CC 4.0 BY- ...

随机推荐

  1. Extjs 4.2 右键菜单树节点(,选择逆,废除)

    写自己的最新版本号extjs4.2树节点的操作,记录它,可能在将来被用于. var tree = new Ext.tree.TreePanel({ flex: 1, animate: true, au ...

  2. 使用reserve要再次避免不必要的分配

     关于STL容器,最了不起的一点是,它们会自己主动增长以便容纳下你放入当中的数据,仅仅要没有超出它们的最大限制就能够.对于vector和string,增长过程是这样来实现的:每当须要很多其它空间时 ...

  3. quick-cocos2d-x游戏开发【6】——制作您自己的自定义效果button菜单

    前面提到的主菜单使用,还是很easy的,但我们在商业产品.经常看到button他们人很好,照片不仅就好了,和动画也很不错.Candy Crash都玩过吧,他们看到,button.真的像果冻,效果确实非 ...

  4. hdu 3068 最长回文(manachar模板)

    Problem Description 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.回文就是正反读都是一样的字符串,如aba, abba等   Input 输 ...

  5. 通过私有协议Chrome浏览器页面打开本地程序

    近期方有这样的要求:这两个系统,根据一组Chrome开展,根据一组IE开展,需要Chrome添加一个链接,然后进入IE该系统的开发.这,需要Chrome跳转到创建一个链接IE浏览器指定的页面.同时也实 ...

  6. 华为机试 之 joseph环

    一:首先科普一下约瑟夫问题的数学方法 (1)  不管是用list实现还是用vector实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比較烦,并且时间复杂度高达O(nm),当n,m很大(比如上百 ...

  7. UVA11627-Slalom(二分法)

    题目链接 题意:有n个宽为w的旗门,第i个旗门左端的坐标为(xi, yi),对于全部1 <= i < n满足yi < y(i+1).你有s双滑雪板,第j双的速度为sj(垂直向下的速度 ...

  8. android 反编译(dex 和 odex),非脑残转帖,绝对可靠

    Android 反编译 反编译odex文件(比如framework.odex),若是反编译dex,直接第4步 1.因为反编译odex的工具在D:\Develop tools\android反编译工具\ ...

  9. Access to the temp directory is denied. Identity 'NT AUTHORITY\NETWORK SERVICE' under which XmlSerializer is running does not have sufficient permiss

    造成错误的原因是用bat代码清理系统垃圾时造成的权限丢失而引起的 错误描述 1.An error occurred creating the configuration section handler ...

  10. Python超级明星WEB框架Flask

    Flask简介 Flask是一个相对于Django而言轻量级的Web框架. 和Django大包大揽不同,Flask建立于一系列的开源软件包之上,这其中 最主要的是WSGI应用开发库Werkzeug和模 ...