托管程序的执行模型大致如下:

  1. 编译源代码为程序集(dll或exe文件),程序集包括了记录相关信息的元数据IL代码
  2. 执行程序集文件时,启动CLR,JIT负责把IL编译为本地代码并执行

IL是微软推出的一种面向对象的类似汇编指令集合的中间语言,无论是C#还是VB代码,经过不同的编译器可编译为无差别的IL,或者说单看IL代码是无法分辨出它是来自C#还是VB,IL类似于Java的.Class文件,该文件具有平台无关性,这使得.Net程序具备了像Java那样跨平台的条件。

程序集的组成及编译

程序集就是平时我们看到的由源代码编译产生的dll或exe文件,程序集是一个windows PE文件,和Java界的jar文件差不多在一个逻辑层次上。

下面来分别介绍程序集的组成结构以及如何从源代码编译为一个程序集:

程序集的组成部分

一个程序集文件的组成如下:

PE头

包括如下信息:文件运行在32位系统还是64为系统上;文件类型是GUI,CUI还是DLL,文件的生成时间等

CLR头

包含以下信息:CLR版本;入口方法;元数据,资源的位置等

清单

包含了程序集本身的一些信息,如:名称,版本,模块,资源等

元数据

包含以下信息:源代码定义的类型和成员;源代码应用的类型和成员,Vistual studio的智能感知就是靠读取元数据实现的

IL代码

如题

资源

嵌入程序集的图片,声音等资源

模块

上述的内容都包含在模块中,一个程序集文件可以包含一到多个模块,可以手动使用csc命令编译多模块程序集,使用Visual studio 编译的程序集默认都是单模块的,关于更详细模块的介绍可以看这本书:《.NET之美:.NET关键技术深入解析

欲了解程序集文件更详细的内容,请参考博客园牛人Anders Liu多年前制作的工具,这个工具可以打开一个程序集文件,查看里面的结构。目前Anders Liu又在GitHub上面创建了新项目peviewer,基于.Net core。

编译源代码为程序集

编程简单程序如下:

public class Program
{
public static void Main()
{
System.Console.WriteLine("Hello");
}
}

保存为d:\test\program.cs,打开“VS2015 开发人员命令提示”,执行如下命令:

csc.exe /out:d:\test\program.exe \t:exe \r:MsCorLib.dll d:\test\program.cs

执行该命令即可生产程序集program.exe文件。上述命令中,/out:后面为要生成的程序集文件名称,\r:后面为要引用的程序集文件名,上述程序中的System.Console类即包含于此dll文件中,由于MsCorLib.dll是.Net Framwork最为核心的程序集,编译器默认加载,所以上面的程序也可省略\r:选项。\t:选项表示生成的程序集的类型,可以接“exe”或“winexe”,前者表示生成的是一个控制台程序集,后者表示生成的是图形界面程序集,由于编译器默认的选项就是“exe”,所以上述命令中/t:选项也可省略。省略后的命令如下:

csc.exe /out:d:\test\program.exe d:\test\program.cs

另外一个重要的概念是“respones file”,在csc.exe文件所在目录,即C:\Windows\Microsoft.NET\Framework\vX.X.X下面,有一个名称为csc.rsp的文件,该文件被称为“respones file”,其默认内容如下:



正如你想象的,执行csc.exe时,该命令会自动读取这个文件中记录的选项,可以修改此文件加入自己想要的选项,也可以自己新建一个respones file 如“myrsp.rsp",然后像这样执行命令:

csc.exe @d:\test\myrsp.rsp /out:d:\test\program.exe d:\test\program.cs

更多的命令选项请看这里:https://msdn.microsoft.com/en-us/library/2fdbz5xd.aspx

运行程序集

托管代码的运行需要寄宿于操作系统提供的非托管的进程中,执行exe文件启动一个进程,该进读取CLR头后加载CLR,CLR启动后接管后续操作,包括内存管理,垃圾回收,异常管理等,在一个操作系统进程内部CLR又维护了一个或多个相当于轻量级进程被称为App Domain的逻辑隔离,不过,通常的程序大部分都是一个App Domain,关于App Domain的介绍可以参考:

CLR使用JIT编译器编译IL为本地CPU指令,JIT编译器可根据CPU的不同而生成不同的CUP指令,仅当方法被一次执行时才会被编译为CUP指令,再次执行则读取编译好的指令。这也是为什么.Net程序在刚启动时较慢的原因,一个解决办法是使用NGen.exe工具直接将IL编译为本地CPU指令,但是存在一个同步的问题,及如果执行环境(换了CPU,CLR版本变化等)改变了,原来编译好的指令可能无法运行。另外使用NGen.exe编译来的CPU指令不会像JIT那样了解CPU的特点而能生成较为优化的指令,所有执行效率要低一些。

参考资料

  • 《CLR via C#》
  • 《.NET之美:.NET关键技术深入解析》

CLR via C# 摘要一:托管程序的执行模型的更多相关文章

  1. C++手动加载CLR运行托管程序(CLR Hosting)

    转载自:http://www.linuxidc.com/Linux/2012-10/72293.htm 机制介绍 有些时候主程序是通过C/C++实现的,但是我们希望通过托管代码来扩展非托管程序,从而也 ...

  2. CLR via C# 摘要二:IL速记

    最简单的IL程序 .assembly test {} .method void Func() { .entrypoint ldstr "hello world" call void ...

  3. 通过修改CoreCLR中的ClrHost实现自托管程序

    上一篇我们讲了如何在windows和Linux上编译CoreClr的问题 虽然文章使用的是windows 10 (Bash)环境,但是也可以做为ubuntu环境的参考. 成功编译CoreCLR的源代码 ...

  4. 重温CLR(十五) 托管堆和垃圾回收

    本章要讨论托管应用程序如何构造新对象,托管堆如何控制这些对象的生存期,以及如何回收这些对象的内存.简单地说,本章要解释clr中的垃圾回收期是如何工作的,还要解释相关的性能问题.另外,本章讨论了如何设计 ...

  5. 托管程序调用非托管dll问题总结

    托管程序Visual Basic.net, 非托管DLL标准C++程序(使用VC++编译) 函数调用定义 第一种写法: <DllImportAttribute("XXX.dll&quo ...

  6. CLR 的执行模型(2)

    第一章 CLR 的执行模型(2) 本篇内容大纲 Framework 类库(Framework Class Library , FCL) 通用类型系统(Common Type System,CTS) 公 ...

  7. CLR执行模型

    好好学习底层运行机制,从CLR via C# 开始. CLR的执行模型: CLR:Common Language Runtime,是一个可由多种编程语言使用的"运行时".CLR的核 ...

  8. 【C#进阶系列】01 CLR的执行模型——一个Hello World的故事

    好吧,废话少说,先上一章Hello World图: 我们有了一个Hello world程序,如此之简单,再加上我今天没有用汉字编程o(>﹏<)o,所以一切很简单明了. 故事开始: 编译: ...

  9. 01.由浅入深学习.NET CLR 基础系列之CLR 的执行模型

    .Net 从代码生成到执行,这中间的一些列过程是一个有别于其他的新技术新概念,那么这是一个什么样的过程呢,有什么样的机制呢,清楚了这些基本的东西我们做.Net的东西方可心中有数.那么,CLR的执行模型 ...

随机推荐

  1. 这些.NET开源项目你知道吗?.NET平台开源文档与报表处理组件集合(三)

    在前2篇文章这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧 和这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧!(第二辑)中,大伙热情高涨.再次拿出自己的私货,在.NET平台 ...

  2. Java中Comparable与Comparator的区别

    相同 Comparable和Comparator都是用来实现对象的比较.排序 要想对象比较.排序,都需要实现Comparable或Comparator接口 Comparable和Comparator都 ...

  3. [原]Paste.deploy 与 WSGI, keystone 小记

    Paste.deploy 与 WSGI, keystone 小记 名词解释: Paste.deploy 是一个WSGI工具包,用于更方便的管理WSGI应用, 可以通过配置文件,将WSGI应用加载起来. ...

  4. 超全面的.NET GDI+图形图像编程教程

    本篇主题内容是.NET GDI+图形图像编程系列的教程,不要被这个滚动条吓到,为了查找方便,我没有分开写,上面加了目录了,而且很多都是源码和图片~ (*^_^*) 本人也为了学习深刻,另一方面也是为了 ...

  5. SQL Server 批量删除存储过程

    原理很简单的'drop proc xxx'即可,下面有提供了两种方式来删除存储过程,其实本质是相同的,方法一是生成删除的sql后直接执行了,方法二会生成SQL,但需要检查后执行,个人推荐第二种做法. ...

  6. MySQL+Amoeba实现数据库主从复制和读写分离

    MySQL读写分离是在主从复制的基础上进一步通过在master上执行写操作,在slave上执行读操作来实现的.通过主从复制,master上的数据改动能够同步到slave上,从而保持了数据的一致性.实现 ...

  7. 编写一个通用的Makefile文件

    1.1在这之前,我们需要了解程序的编译过程 a.预处理:检查语法错误,展开宏,包含头文件等 b.编译:*.c-->*.S c.汇编:*.S-->*.o d.链接:.o +库文件=*.exe ...

  8. Linux设备文件简介(转载)

    Linux 中的设备有2种类型:字符设备(无缓冲且只能顺序存取).块设备(有缓冲且可以随机存取).每个字符设备和块设备都必须有主.次设备号,主设备号相同的设 备是同类设备(使用同一个驱动程序).这些设 ...

  9. How to accept Track changes in Microsoft Word 2010?

    "Track changes" is wonderful and remarkable tool of Microsoft Word 2010. The feature allow ...

  10. 转: 如何高效利用GitHub

    注:写了很多使用哲学,有意思 from: http://www.yangzhiping.com/tech/github.html