前言

一直都用集成开发坏境(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,元数据。这是一个很重要的概念,使得咱们的托管模块有自我描述的能力。这个地方包含的都是咱这个模块里面的元素,类型,方法,变量等,另外如果还有引用别的模块的类似这些信息。这是区别于非托管模块的一个重要点:

  1. Dev10(微软内部的说法,指visual studio 2010)的编码智能提示,你输入一个点或者ctrl+j快捷方式,就能列出所有可用的类型和成员来。该功能就依赖于此;
  2. 咱有对象的序列化和反序列化(XML或者Binary的格式)也需要依赖于元数据对对象结构的描述。WCF的数据契约DataContract,WWF的工作流状态持久化机制,很多。
  3. 元数据里面存了对别的对象的引用,所以可以在运行时再加载需要的对象(通过JIT编译),这使得我们不需要再像其他非托管模块编译的时候需要把其他被引用模块一起编译进来。
  4. 咱重要的垃圾回收机制(GC)的实现也依赖于此,想必大伙都对这机制不会陌生,说是当一个对象没有被再引用的时候会被标志城可回收的,就像清洁工阿姨判断这个物品时别人丢弃的还是暂时存放在地上的,然后清洁工阿姨会根据自己的判断来清理这些东西。但是当一个对象对进行回收处理的时候,该对象引用的其他需要被回收的对象abc也需要被回收掉,这个时候就可以通过咱的元数据去定位abc了。
  5. 等等

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)的更多相关文章

  1. C# 程序集Assembly

    原谅我到目前为止一直肤浅的认为程序集就是dll,这种想法是错误的. 今天就系统的学习记录一下“程序集”的概念.原文链接https://www.cnblogs.com/czx1/p/2014131370 ...

  2. 【C#基础概念】程序集与托管模块的概念

    本文是为了学习程序集而整理的网上资料,主要包括两个部分,概念和使用,前部分讲怎样理解程序集,后部分讲述怎样使用的细节. 程序集与托管模块的概念 "程序集与托管代码块"(摘自Hima ...

  3. .NET 程序集Assembly使用

    概述 一直以来,我们都在用C#编写程序,编写程序的时候,我们用到继承.多态.接口以及泛型,我们也都明白子类可以继承抽象类,并能够重写父类的抽象方法,可是大家是否想过,如下几个问题: 1.凡树必有根和叶 ...

  4. 【C#进阶系列】02 PE文件,程序集,托管模块,元数据——还是那个Hello world

    好了,还是这张图,还是一样的Hello world. 因为本章其实很多都是讲一些命令行编译啊什么鬼的配置类的东西,要用的时候直接百度或者回头查书就可以了, 所以了解一下也就行了,也没有记录下来,接下来 ...

  5. Axis2(9):编写Axis2模块(Module)

    Axis2可以通过模块(Module)进行扩展.Axis2模块至少需要有两个类,这两个类分别实现了Module和Handler接口.开发和使用一个Axis2模块的步骤如下: 1. 编写实现Module ...

  6. 多模块项目Module must not contain source root. The root already belongs to module

    多模块项目Module "*" must not contain source root *. The root already belongs to module "* ...

  7. Angular之特性模块 ( Feature Module )

    项目结构 一 创建特性模块,及其包含的组件.服务. ng g module art ng g component art/music ng g component art/dance ng g ser ...

  8. (转)关于ES6的 模块功能 Module 中export import的用法和注意之处

    关于ES6的 模块功能 Module 中export import的用法和注意之处 export default 的用法 export default命令用于指定模块的默认输出.显然,一个模块只能有一 ...

  9. 【angularJS】定义模块angular.module

    模块定义了一个应用程序.控制器通常属于一个模块. JavaScript 中应避免使用全局函数.因为他们很容易被其他脚本文件覆盖. AngularJS 模块让所有函数的作用域在该模块下,避免了该问题. ...

随机推荐

  1. 【原创】MapReduce运行原理和过程

    一.Map的原理和运行流程 Map的输入数据源是多种多样的,我们使用hdfs作为数据源.文件在hdfs上是以block(块,Hdfs上的存储单元)为单位进行存储的. 1.分片 我们将这一个个block ...

  2. java 正则表达式(内附例子)

    前言:最近工作中遇到了大量用正则表达式的情况,需要用一定的规则匹配字符串,然后提取里面的数据,格式化后转成自己想要的格式.所以作为一个菜鸟是时候再来巩固一下正则表达式了.转载请注明出处:https:/ ...

  3. JS实现继承的几种方式以及优缺点(转载)

    前言 JS作为面向对象的弱类型语言,继承也是其非常强大的特性之一.那么如何在JS中实现继承呢?让我们拭目以待. JS继承的实现方式 既然要实现继承,那么首先我们得有一个父类,代码如下: // 定义一个 ...

  4. 【代码笔记】iOS-单击手势的添加

    一,效果图. 二,工程图. 三,代码. RootViewController.h #import <UIKit/UIKit.h> @interface RootViewController ...

  5. css points

    <style type="text/css" rel="stylesheet">.a{ width:500px; height:400px;对放置图 ...

  6. 使用Keras进行多GPU训练 multi_gpu_model

    使用Keras训练具有多个GPU的深度神经网络(照片来源:Nor-Tech.com). 摘要 在今天的博客文章中,我们学习了如何使用多个GPU来训练基于Keras的深度神经网络. 使用多个GPU使我们 ...

  7. Java实验案例(接口)

    实验任务 任务一:设计实现发声接口 任务二:动物乐园 实验内容 任务一:设计实现发声接口 任务目的: 理解并掌握如何定义接口 掌握接口的实现方式 任务描述: 设计和实现一个Soundable接口,该接 ...

  8. js异步原理与 Promise

    一.Javascript的异步原理 javascript 是单线程语言,所以同一时间只执行一个运算.但有些方法是不能瞬间完成或不可预知何时完成的(如网络请求.settimeout等),为了让它们不对后 ...

  9. 网络 IP地址、网段、子网掩码

    IP地址范围,最小:00000000,00000000,00000000,00000000:最大:11111111,11111111,11111111,11111111 即:最小:0.0.0.0 最大 ...

  10. ES6-let & const

    let和const命令 let 它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效. for(let i = 0; i < arr.length; i++){} 用let命 ...