快速理解.NET Framework
引言
本文着眼于微软.NET框架。这是较新发布的软件开发环境,它帮助开发者快速开发应用程序并且提供各种不同语言像Visual Basic .NET, C#, ASP .NET, 和Jscript .NET等开发最合适的,高效的,可扩展的,面向性能的应用程序 。
.NET框架概述 .NET框架是一种新的计算平台,它在Internet高度分布的环境中简化应用程序开发
服务
NET框架提供以下服务:
开发软件应用工具 执行软件应用的运行时环境 服务器基础设施 帮助开发者减少编码提高工作效率的增值只能软件 .NET框架将使开发者为不同设备和不同平台开发应用程序,如:windows应用程序、web应用程序、windows服务和web服务。
目标
设计.NET框架是为了实现下列目标:
一个一致的面向对象编程环境,目标代码能本地化存储和执行,本地化执行而不是分布式Internet,或者远程执行。 一个减少软件部署和版本冲突的代码编辑环境。 一个确保安全的代码执行的代码编辑环境,包括来自未知的或是不能完全信任的社团的代码。 一个能消除脚本的或解释性的环境引起的性能问题的代码编辑环境。 开发者在面对大量不同应用系统类型时有一致的开发体验,如基于Windows的应用程序和基于Web的应用程序。 构造所有工业标准信息来确保基于.NET框架的代码能够集成任何其他代码。
理解.NET框架体系结构
.NET框架有两个组件:.NET框架类库和公共语言运行时。 .NET框架类库使类型(CTS)变的简单,它对于.NET语言来说是公共的。 公共语言运行时组成部分有由:(类加载器)加载程序的IL代码并将起编译成本地代码到运行时,执行和管理代码来加强安全和类型安全,并且提供线程支持。
.NET框架体系结构最顶部是像VB .NET C#, VJ#, VC++ .NET之类的语言;开发者能开发(使用上面的任何语言)像Windows窗体,Web窗体,Windows服务和XML Web服务。
理解.NET框架的角色
.NET框架有两个组要的组件:公共语言运行时(CLR)和.NET框架类库。公共语言运行时是.NET框架的基础。CLR 在运行时管理代码,提供像内存管理,线程管理和remoting之类的核心服务,同时也加强严格的类型安全和促进代码正确来确保程序的安全性和健壮性(鲁棒性)。代码管理的概念是CLR的基本原则。针对CLR的代码被认为是可管理的代码,而不是针对CLR的代码则被认为是不可管理的代码。
类库是.NET框架的一个完整的组件, 包括可重用类的面向对象集合,它使我们能用来开发应用程序包括传统的命令行或是任何像Windows窗体,ASP. NET Web窗体和新近发明的XML Web 服务的Windows服务这样的图形用户接口(GUI)。
欧洲计算机制造商协会(ECMA)标准定义了通用语言规范(CLS);这加强了软件开发语言能够进行互操作。按照CLS编写的代码应该能和另一个符合CLS语言的代码一起编译。因为由符合CLS语言支持的代码将会被编译成中间语言(IL)代码。CLR引擎执行IL代码。这保证了符合CLS语言的互用性。微软.NET框架支持的语言有Microsoft Visual Basic .NET, Microsoft Visual C#, Microsoft Visual C++ .NET, and Microsoft Visual J# .NET.
语言编译器生成中间语言代码,叫做微软中间语言(MSIL),它使不同可互操作的.NET语言编写程序。 ECMA标准,公共语言架构(CLI),定义了IL代码需要执行的基础架构的规范。CLI提供一个公共类型系统(CTS)和像类型安全,可管理的代码执行和side by side执行的服务。
图1.微软.NET框架的ECMA标准
.NET框架提供基础架构和服务。CLI规范.它们包括: 公共语言运行时:
CLR包括CLI
CLR也提供.NET应用程序的执行环境
公共类型系统:
提供数据类型,值,对象类型。这使得开发人员能用不同的语言开发应用程序。.NET语言共享CTS意味着所有在应用程序中的类型在CLI类型定义中是一样的。
类型安全:
.NET框架在值和对象上执行操作,因为.NET框架需要知道每个值和对象的类型并且引用值和对象类型。
可管理的代码执行
.NET框架管理执行.NET应用程序时对象的状态。
.NET框架自动分配内存并提供来机收集机制来重新分配内存
Side-by-side执行
.NET框架通过使用不同版本的装配器允许同一应用程序的不同版本运行在同一机器上。装配器由IL代码和元数据组成。元数据决定应用程序的依赖关系。通过这个,.NET框架运行时能执行多种版本装配器并且解决遗留的开发环境的主要问题。那就是DLL HELL?
.NET装配器
图2 Side-by-side执行
理解.NET框架CLR
公共语言运行时:
运行时环境 CLR把应用程序编译成有运行时,把IL代码编译成本地代码,执行代码 运行时服务 内存管理 类型安全 增强安全 异常管理 线程支持 调试支持 理解.NET框架CLR的体系结构
类加载器,将类加载到CLR。 MSIL到本地代码的编译,将把MSIL转变成本地代码。 代码管理器,它在代码执行期间进行管理。 内存分配和垃圾收集,表现为自动内存管理。 安全的引擎,使用微软提供的工具和在控制面板对.NET框架配置加强安全限制包括代码级安全、文件及机器级安全。 类型检查器,增强强类型检查。 线程支持,提供对应用程序的多线程支持。 异常管理器,提供对运行时异常处理的机制。 调试引擎,允许开发者调试应用程序的不同类型。 COM配置,允许.NET应用程序与COM应用程序交换数据。 基类库支持,提供应用程序运行时所需的类。 公共语言运行时的特征
CLR有以下特征:
管理内存: 内存分配 内存的重分配(垃圾收集) 线程执行支持 代码执行 代码安全检查 编译 MSIL到本地代码 基于信任的代码安全(对执行代码的授权。代码级,文件级,机器级)这些特征对运行在公共语言运行时的可管理代码来说是固有的。 理解CLR
为了执行程序并且获得可管理执行环境的所以好处,我们用CLS支持的.NET框架语言编写代码。语言编译器将源代码编译成由CPU相关的代码和平台相关的指令组成的MSIL代码。MSIL有下列组成:
能够执行算术和逻辑运算的指令。 直接访问内存。 控制执行流 处理异常 MSIL代码能够在执行前被编译成特定CPU指令,CLR所需要代码的信息只有元数据。元数据描述代码并且定义代码类型包括引用代码在运行期用到的其他类型。 一个装配器由精简的可执行文件组成。当执行PE文件的时候类加载器价载MSIL代码而元数据把精简的可执行文件编成运行时内存。 PE文件执行之前它将代码传递到本地代码编译器进行编译,IL到本地代码的编译是有JIT编译器完成的。因为不同的CPU架构和编译器 IL代码到本地指令。
CLR的特点
被管理的多线程支持和线程监控。应用程序域包括一个或多个执行线程。 管理不安全代码的互用性,和COM配置。 结构化的异常处理机制 基础架构和被管理执行进程,内存管理和垃圾收集 CLR的结构
基类库支持支持所有使用.NET语言来支持基本功能性的基类。 COM配置支持COM对象间数据的重组。 异常管理支持使用try catch finally语句块在运行时处理错误。 安全引擎在运行时加强安全规则。 类型检查器在运行时作类型安全检查。 调试引擎支持运行时调试。 代码管理器管理运行时被管理代码 IL到本地代码编译器将MSIL代码编译成机器相关的本地代码 垃圾收集器支持内存管理并支持清理运行时废弃的内存。 类加载器在运行时加载类。 理解JIT编译器
JIT编译器作为CLR的一个完整的部分将MSIL代码编译成本地代码并且实时执行整批代码。代码将会被缓存而下次就会从缓存中读取代码再次编译执行(翻译不出来)
JIT执行进程
CLR类加载器加载MSIL代码并且将元数据加载到内存;代码管理器调用WinMain或DllMain方法。JIT编译器在其入口方法执行之前编译这个方法。代码管理器将对象放置在内存中并控制代码的执行。垃圾收集器实现对管理堆的周期性检查识别应用程序的无效对象。
程序执行时类型检查器确保所有对象和值以及对象和值的引用有其合法的类型。类型检查器也保证代码的唯一合法操作,否则就抛出异常。代码在运行时由CLR控制。CLR在以下行为上增强安全性:
像硬盘一样控制和访问系统资源 控制和访问网络连接 控制和访问其他硬件资源 被管理代码执行
被管理代码执行被认为是由CLR执行的进程,具体有以下几个方面:
CLR加载MSIL和应用元数据 CLR执行本地代码, CLR提供自动内存管理 被管理的执行也实现JIT编辑 封装类型安全, 增强安全性 处理异常 被管理的执行进程
被管理代码是自解释性的代码,它在.NET框架中给CLR多运行时服务的信息。 这些信息在PE文件里以元数据的形式被存储在MSIL代码中。元数据信息会描述代码包含的类型。 被管理数据是由垃圾收集器自动被分配和释放的。被管理代码能被被管理数据理解而非管理数据能被被管理理解。(翻的不正确) 内存管理
自动内存管理意味着当对象创建时不需要编写代码分配内存或是当应用程序不需要对象时释放内存。 自动内存管理的进程包括下列任务:
?分配内存
当一个进程被初始化时,运行时保留了一个连续的地址空间而不为它分配任何存储空间。 这个保留的地址空间被叫做托管堆。托管堆在下一个对象被放置的地方保留了一个指针。 当一个应用程序使用new操作符创建一个对象时,new操作符检查堆内对象所需的内存是否可用。 当下一个对象创建的时候,垃圾收集器在托管堆分配内存给对象。 在托管堆分配内存给对象的时间比分配非托管堆内存耗时要少。 在非托管堆中,指向内存的指针在链表数据结构中维护。因此,分配内存需要通过操纵链表,寻找能够容纳它的较大的内存块。(此处原文不全) 与访问非托管内存相比你能更快地访问托管内存的对象,因为在托管内存分配时,对象总是在托管的地址空间中分配。 ?释放内存
垃圾收集器周期性地应用程序不再需要的对象中释放内存。 每个应用程序有一组根指针。根指针指向在托管堆存储位置。每个根指针或者引用托管堆中的一个对象或是被置成空。 一个应用程序的根指针由线程栈上的全局静态指针,局部变量和引用对象参数组成。 JIT编译器和运行时维护应用程序根指针的列表。垃圾收集器使用这个列表创建从根指针列表中获得的在托管堆中的对象图表。 当垃圾收集器开始运行,它把在托管堆中的所有对象都看作垃圾。 垃圾收集器通过应用程序的根指针列表操作,这个列表定义了在应用程序根指针列表中有相应的引用的对象并对可获得的对象标记。 垃圾收集器也把这样的对象作为可获得对象。(不知道是什么意思) 垃圾收集器认为所有托管堆中不可获得的对象是垃圾。 垃圾收集器通使用收集进程释放垃圾对象空间。 垃圾收集器使用内存复制功能来压缩托管堆中的对象。 垃圾收集器更新应用程序根指针列表中的指针,使得指向较早的应用程序根指针正确指向对象。 垃圾收集器使用高度优化的机制完成垃圾收集。它把托管堆中的对象分为三级:0、1、和2。第0级包括最近被创建的对象。 垃圾收集器开始在第0级收集不可获得的对象。接着,垃圾收集器紧缩内存并将可获得对象提升为第1级。 幸免于收集进程收集的对象被提升为更高的级别。 垃圾收集器在第1级和第2级搜索不可获得的对象,仅当通过第0级对象的收集进程释放的内存不足以创建一个新的对象时。 垃圾收集器为所有应用程序创建的托管对象管理内存。 垃圾收集器能通过在对象等Dispose方法中提供清除代码来显式释放这些系统资源。 我们在对象完成工作后需要显式调用Dispose方法。 ?实现完成器
完成器进程允许一个对象在垃圾收集器启动之前完成清理工作。 Finalize方法确保了即使客户没有显式调用Dispose方法,所使用的资源在对象被垃圾收集时也会从内存被释放。 在垃圾收器集进行垃圾收集时识别对象是垃圾后,它在释放内存前调用对象的Finalize方法。 完成器是包含在对象收集之前被执行的清理代码的方法。执行清理代码的进程被叫做终结。Dispose和Finalize方法被叫做完成器。 对象的Dispose方法会释放所有资源,包括它的父对象拥有的资源通过调用父对象的Dispose方法。 我们有两个方法执行Dispose方法: 类用户能够调将被销毁对象的Dispose方法,或者 Finalize方法能在终结过程中调用Dispose方法。
未
|