程序集(Assembly)和模块(Managed Module)
前言
一直都用集成开发坏境(IDE),一直对模块和程序集的概念理解的不是很直观,因为一Build就把你的单个模块塞进程序集里面去了。当然,对你的编程也不会造成太大的影响。但有些东西你最好还是知道比较好,而且对安装部署你的应用程序一定条件下有帮助。
首先我们先来认识下托管模块(Managed Module)。PE头+CLR头+元数据metadata+IL。想必关于这个结构应该不会很陌生。还是费点笔墨介绍一下:
1, PE头,这是标准的window PE头吧,顺序结构的,是否是32位的,是CUI还是GUI的,还是library的等信息。刚写完一段代码利用这里的信息来编码判断文件是基于32还是64的。
2, CLR头呢,自然是CLR要用的,里面有CLR的版本信息,若是可执行程序的话,入口函数main位置信息,还包含了下面将要提到的metadata的位置信息等。
3, Metadata,元数据。这是一个很重要的概念,使得咱们的托管模块有自我描述的能力。这个地方包含的都是咱这个模块里面的元素,类型,方法,变量等,另外如果还有引用别的模块的类似这些信息。这是区别于非托管模块的一个重要点:
- Dev10(微软内部的说法,指visual studio 2010)的编码智能提示,你输入一个点或者ctrl+j快捷方式,就能列出所有可用的类型和成员来。该功能就依赖于此;
- 咱有对象的序列化和反序列化(XML或者Binary的格式)也需要依赖于元数据对对象结构的描述。WCF的数据契约DataContract,WWF的工作流状态持久化机制,很多。
- 元数据里面存了对别的对象的引用,所以可以在运行时再加载需要的对象(通过JIT编译),这使得我们不需要再像其他非托管模块编译的时候需要把其他被引用模块一起编译进来。
- 咱重要的垃圾回收机制(GC)的实现也依赖于此,想必大伙都对这机制不会陌生,说是当一个对象没有被再引用的时候会被标志城可回收的,就像清洁工阿姨判断这个物品时别人丢弃的还是暂时存放在地上的,然后清洁工阿姨会根据自己的判断来清理这些东西。但是当一个对象对进行回收处理的时候,该对象引用的其他需要被回收的对象abc也需要被回收掉,这个时候就可以通过咱的元数据去定位abc了。
- 等等
4, IL, intermediate language,是介于高级编程语言和计算机指令的中间态指令。如何产生?语言编译器产生,用C#得都熟悉CSC.exe命令,该命令可以把你写的helloword程序转化成IL。如何执行?这就有依赖于前面提到过的JIT编译器了。简单的一句话表达:当代码块别第一次执行的时候会执行实时编译,然后把metadata指向的该方法内存地址替换掉,然后再执行该方法内存空间上的指令,所以第二次执行的就不需要编译了。写到这里,我想到了两个问题,一个是性能问题,另外一个是编译粒度问题。不妨简单的来讨论一下:
性能问题。
把IL编译成计算机指令,当然会有性能消耗,这个好像也是非托管和托管之间争议的最大的地方吧,非托管就直接编译成计算机指令了,就能直接执行了。托管的还需要再被编译一次,虽然这个过程作了优化,也相信微软一直会不断优化这个过程,总归有性能方面的担心,很正常。这种差异肯定是客观存在的,不过下面的一些介绍会些许减少一些你的顾虑吧:
i. 在介绍时候被提到了就是一个代码块只会被编译一次,第二次就直接使用计算机指令了。看到这个你是不是有了一些想法,对的编程是不是起到了一定的作用?想说的是合理的代码结构设计和编程习惯,会让你的代码变快。还不明白的话就举个具体例子,当你要实现像个类似功能,他们80%的逻辑是一样的,试着把公共模块抽离出来做成一个可能只有参数差异的方法供这些功能调用,不管是从维护还是从性能的角度您都提高了你的性能。(当然事情并非那么绝对。为了不误导各位,这里不得不提的是方法内联的编译优化概念。具体的请自己查阅或关注近期更新的博客,篇幅太长不适合阅读)
ii. 第二个想说的是我们可以充分JIT的智能优化,最直观的是最CPU指令的优化,不同类型CPU对处理同一个动作有不同的适合自己的最优化指令,JIT可以做到这个。为什么单独拿出来说这个,因为这个是相对于静态非托管编译的一个很大的优化。哦,你懂了。
iii. 当然你如果还是心存芥蒂的话,其实没关系,在SDK目录下面有一个命令教NGen.exe,对了,可以把IL直接转化成计算机指令,关注以后的博客更新会有提到如何使用以及注意事项。
编译的粒度问题。
对于动态编译执行的代码,选择在何时编译,编译多少相关的代码块,这种时机和粒度的选择是于性能和计算机资源利用效率是至关重要的。(写着写着又篇幅过长了,打算留到后面再作介绍)
认识完托管模块的结构后,再来看看程序集Assembly。
看到这个集,就知道是个集合,程序集,就是很多程序的集合,那程序文件是什么,就是上面我们提到的模块,当然能被称作程序文件的不只是模块啦,还有资源文件类的,图标,本地化语言包等。所以啊,一个或者多个程序文件就构成了我们的程序集。放心,这里介绍的程序集的概念不会太多打破你之前的认识。只是再稍作介绍而已。
当我们用命令行得到一个test.exe的时候,这就是一个程序集,只是是一个单个模块没有资源文件的程序集。
Csc /out:test.exe /t:exe program.cs
这里你想到怎么让一个程序集能有多个模块呢,又怎么能够有包含资源文件呢?咱接着输入命令行:
Csc /t:module testmodule.cs
你就会得到一个testmodule.netmodule的文件,没见过吧,这就是一个模块文件,你可以同样的方式得到另外一个模块文件然后在用AL.exe把两个模块文件编译进一个程序集mergedAssemly.dll:
Al /out:mergedAssemly.dll /t:library testmodule.netmodule testmodule1.netmodule
这里有几点注意的是:
- al.exe /t的类型只能是library,想啊,如果是exe或者winexe的话,你都没指定入口函数呢(你也可以用al.exe指定入口函数的用法)。
- 这里程序集的执行还是依赖于物理的.netmodule文件的,并没有把模块文件内嵌到程序集里面去,这给你了条件可以按需部署你的程序了。
- Assembly 的metadata里面专门有一个是manifest的区域空间,清单嘛,想想应该也知道是用来包含该程序集里面的程序文件的信息的。
- 当然csc.exe和al.exe还能做很多事情,不一一举例了,为什么单独build一个模块文件的目的也在于更直观的让大伙体会到两者的关系。
- 对于CLR来说,是不能直接使用Module的。Assembly是一个重用的单元,有自己的版本和安全信息的保护。
程序集(Assembly)和模块(Managed Module)的更多相关文章
- C# 程序集Assembly
原谅我到目前为止一直肤浅的认为程序集就是dll,这种想法是错误的. 今天就系统的学习记录一下“程序集”的概念.原文链接https://www.cnblogs.com/czx1/p/2014131370 ...
- 【C#基础概念】程序集与托管模块的概念
本文是为了学习程序集而整理的网上资料,主要包括两个部分,概念和使用,前部分讲怎样理解程序集,后部分讲述怎样使用的细节. 程序集与托管模块的概念 "程序集与托管代码块"(摘自Hima ...
- .NET 程序集Assembly使用
概述 一直以来,我们都在用C#编写程序,编写程序的时候,我们用到继承.多态.接口以及泛型,我们也都明白子类可以继承抽象类,并能够重写父类的抽象方法,可是大家是否想过,如下几个问题: 1.凡树必有根和叶 ...
- 【C#进阶系列】02 PE文件,程序集,托管模块,元数据——还是那个Hello world
好了,还是这张图,还是一样的Hello world. 因为本章其实很多都是讲一些命令行编译啊什么鬼的配置类的东西,要用的时候直接百度或者回头查书就可以了, 所以了解一下也就行了,也没有记录下来,接下来 ...
- Axis2(9):编写Axis2模块(Module)
Axis2可以通过模块(Module)进行扩展.Axis2模块至少需要有两个类,这两个类分别实现了Module和Handler接口.开发和使用一个Axis2模块的步骤如下: 1. 编写实现Module ...
- 多模块项目Module must not contain source root. The root already belongs to module
多模块项目Module "*" must not contain source root *. The root already belongs to module "* ...
- Angular之特性模块 ( Feature Module )
项目结构 一 创建特性模块,及其包含的组件.服务. ng g module art ng g component art/music ng g component art/dance ng g ser ...
- (转)关于ES6的 模块功能 Module 中export import的用法和注意之处
关于ES6的 模块功能 Module 中export import的用法和注意之处 export default 的用法 export default命令用于指定模块的默认输出.显然,一个模块只能有一 ...
- 【angularJS】定义模块angular.module
模块定义了一个应用程序.控制器通常属于一个模块. JavaScript 中应避免使用全局函数.因为他们很容易被其他脚本文件覆盖. AngularJS 模块让所有函数的作用域在该模块下,避免了该问题. ...
随机推荐
- MyBatis入门(二)—— 输入映射和输出映射、动态sql、关联查询
一.输入映射和输出映射 1. parameterType(输入类型) 1.1 传递简单类型 <select id="getUserById" parameterType=&q ...
- 记一次简单爬虫(豆瓣/dytt)
磕磕绊绊学python一个月,这次到正则表达式终于能写点有趣的东西,在此作个记录: ————————————————————————————————————————————————— 1.爬取豆瓣电影 ...
- python之函数的参数
1.位置参数: 例如计算一个整数的平方: def power(x) return x * x 显然参数x就是一个位置参数,如果要是计算5*5*5..............*5 ,这个函数就太麻烦了, ...
- ES6高频面试题目整理
本篇文章是根据以下内容进行的总结 1.https://segmentfault.com/a/1190000011344301 2.http://www.bslxx.com/a/mianshiti/ti ...
- 【眼见为实】自己动手实践理解数据库READ UNCOMMITED && SERIALIZABLE
目录 准备工作 ①准备测试表和测试数据 ②关闭数据库事务自动提交 ③设置InnoDB存储引擎隔离级别 [READ UNCOMMITTED] [READ UNCOMMITTED]能解决的问题 [READ ...
- zabbix系列之八——安装后配置三Triggers
1Triggers(触发器) 描述 详细 备注 术语描述 1)触发器是评估监控项采集的数据的逻辑表达式,代表了当前系统状态. 2)触发器可定义一个什么数据是可接受的阈值,因此,如果接收的数据超过了可接 ...
- 《图解HTTP》总结 - 思维导图版
对具体内容感兴趣的,可以去 http://www.51test.space/archives/2830 免费下载<图解HTTP>.
- 传递命令行参数示例代码 (C 和 Python)
C语言 在 C 语言中, 使用 main 函数的输入参数 argc 和 argv 传入命令行参数. argc 为 int 类型, 表示传入命令行参数的个数 (argument count); argv ...
- WWF3.5SP1 参考源码索引
http://www.projky.com/dotnet/WF3.5SP1/System/Runtime/Serialization/FormatterServicesNoSerializableCh ...
- Oracle EBS 获取说明性弹性域全局数据元
SELECT b.flex_value_set_id, t.application_column_name, t.form_left_prompt FROM fnd_descriptive_flexs ...