一个托管的程序,从书写代码到编译到最后运行,到底是怎么一个过程,一直有些混沌,好好看了下书,梳理了一下。
托管的程序是二次编译的,因此一个托管程序从第一次编译到最后的运行可以根据这两次编译的目的性不同分成两个阶段。
第一个阶段是从不同的语言编写的代码通过各自不同的编译器编译生成dll和exe文件。第一次编译生成的dll文件和exe文件统称为托管模块。它们由PE表头,CLR表头,IL,元数据几部分组成。PE表头是存放操作系统(Windows)识别模块需要的一些信息;CLR表头是CLR的一些标识信息;IL是中间代码,描述模块中各方法的执行过程;元数据是托管模块的基石,它描述了代码中类型和成员的信息。这些托管模块组合成为程序集(这是一个逻辑概念),程序集中除了托管(可以是1对n,但通常是1对1),还有资源文件和一个描述清单。程序集是程序部署和CLR操作的基本单位,通常安装一个托管程序,就是指将这些程序集部署到机器上(这种说法比较简单,机器还需要环境)。
然后,程序进入第二个阶段,运行阶段。通常运行一个托管程序是从非托管程序(宿主)进入。这时候操作系统会判断PE中的信息,不同的宿主根据不同的方式启动CLR。CLR是以COM服务器的形式安装在机器上的。CLR会初始化应用程序,建立一个应用域AppDomain。应用域中包含程序集和托管堆和栈。应用域是托管程序运行的环境,一个应用域中的程序不能访问其他域的内容(可以通信,可以通过中立域)。程序的运行中需要第二次编译,第二次编译采用JIT(Just In Time)方式(也可以不采用JIT,而提前全部编译),简单的说,就是第一次用到某程序集中某方法的时候,才加载该程序集的该部分,编译之后存放在堆中,下次运行的时候就可以直接调用了。在JIT中有一个不同于非托管程序的重要部分是验证,验证包括很多方面的内容,以保证程序的安全运行。关于JIT的性能问题,在别的文章中我会好好写的。
托管的程序是二次编译的,因此一个托管程序从第一次编译到最后的运行可以根据这两次编译的目的性不同分成两个阶段。
第一个阶段是从不同的语言编写的代码通过各自不同的编译器编译生成dll和exe文件。第一次编译生成的dll文件和exe文件统称为托管模块。它们由PE表头,CLR表头,IL,元数据几部分组成。PE表头是存放操作系统(Windows)识别模块需要的一些信息;CLR表头是CLR的一些标识信息;IL是中间代码,描述模块中各方法的执行过程;元数据是托管模块的基石,它描述了代码中类型和成员的信息。这些托管模块组合成为程序集(这是一个逻辑概念),程序集中除了托管(可以是1对n,但通常是1对1),还有资源文件和一个描述清单。程序集是程序部署和CLR操作的基本单位,通常安装一个托管程序,就是指将这些程序集部署到机器上(这种说法比较简单,机器还需要环境)。
然后,程序进入第二个阶段,运行阶段。通常运行一个托管程序是从非托管程序(宿主)进入。这时候操作系统会判断PE中的信息,不同的宿主根据不同的方式启动CLR。CLR是以COM服务器的形式安装在机器上的。CLR会初始化应用程序,建立一个应用域AppDomain。应用域中包含程序集和托管堆和栈。应用域是托管程序运行的环境,一个应用域中的程序不能访问其他域的内容(可以通信,可以通过中立域)。程序的运行中需要第二次编译,第二次编译采用JIT(Just In Time)方式(也可以不采用JIT,而提前全部编译),简单的说,就是第一次用到某程序集中某方法的时候,才加载该程序集的该部分,编译之后存放在堆中,下次运行的时候就可以直接调用了。在JIT中有一个不同于非托管程序的重要部分是验证,验证包括很多方面的内容,以保证程序的安全运行。关于JIT的性能问题,在别的文章中我会好好写的。
本文转自 duguguiyu 51CTO博客,原文链接:http://blog.51cto.com/duguguiyu/361610,如需转载请自行联系原作者