CLR(公共语言运行库)可以说是整个.NET平台的核心元素.基本上托管应用程序所有的操作都是需要CLR的监管和处理.这些操作包括进程内应用程序的加载, IL语言转换为机器语言, 异常管理, 垃圾回收,加载程序集等等.
CLR执行托管代码前,实际上会创建三个应用程序域, 它们是系统域(System Domain),共享域(Shared Domain)和缺省应用程序域(Default AppDomain).其中系统域和共享域对于托管代码和CLR的宿主程序(如控制台程序,ASP.NET等)不可见.域可以通过AppDomain.CreateDomain方法创建(下文会详细叙述这个过程),在非托管的代码中,可以使用一个ICORRutimeHost的接口创建(这个接口我也没用过,一般都是托管的代码).对于复杂的宿主程序,由网站根据应用程序的数目来建立域。
图1.CLR启动程序创建的域
(转载自Inside .NET Framework:CLR runtime object)
注:下文中的AppDomain特指应用程序域,对于系统域和共享域保持原来的指定
要注意的是,这里的域不同于C#类中域的概念.C#类中域指类和对象相关的变量,这里的域其实是一种轻量的进程,你完全可以把它当成进程来理解.有人也许不明白既然有了进程的概念,干吗又搞出一个域来.其实这是为了实现在服务器中加载多个应用程序才提出的.AppDomain与进程相比优势在于:
1.所需系统资源更少
2.进程之间的AppDomain可以共享资源
但是千万别把AppDomain和线程搞混,这二者之间没有从属的关系.地球人都知道线程是进程的孩子,但是线程和AppDomain的关系类似于正交关系.同一时间内多个线程可以运行在一个AppDomain中,多个AppDomain也可以跨越一个线程.
下面, 我们先大致看一下系统域和共享域的一些基本概念,再着重探讨AppDomain的知识.
系统域(System Domain):系统域初始化共享域和AppDomain。它在共享域中加载了mscorlib.dll()。同时,系统域产生了进程的接口ID(不知道这样描述对不对),以此来创建AppDomain的接口虚拟表映射的接口。在进程中,系统域监控所有的域,加载(load)和卸载(unload)AppDomain也有它完成。可以认为系统域是CLR中的基础域。
共享域(Shared Domain):在.NET中,不是所有的代码都属于某个域,但这些代码却是用户代码所必需的。共享域就负责加载这部分代码。比如大家熟悉的Object,Array,String,delegate等。这些代码在CLR启动程序时先被加载到共享域中.共享域中有一个程序集映射表,通过这个表来查找共享的程序集的依赖关系. 可以认为共享域是CLR中的带有索引的共享文件夹.
注:用户代码和控制台程序也可以加载到共享域.(具体方法?..不急..以后告诉你)
AppDomain
终于说到学习.NET要接触最多的AppDomain了.其实CLR启动应用程序时,就会自动创建一个AppDomain的实例,叫默认的AppDomain(Default AppDomain).大部分的应用程序在运行期间只创建一个域.有些应用程序有多个AppDomain,它们之间由.NET Remoting通信。AppDomain之间是彼此独立的。一个AppDomain无法访问其他的AppDomain的程序集和对象(并不意味着不能相互通信),并且可以定义自己的程序集访问策略。
通过System.AppDomain类的实例,可以获得进程中一个AppDomain的引用:
using System;
using System.Threading;
class MyAppDomain
{
static void Main()
{
Thread.CurrentThread.Name = "MyDomain";
AppDomainSetup info = new AppDomainSetup();
AppDomain myAppDomain = AppDomain.CurrentDomain;
AppDomain newDomain = AppDomain.CreateDomain("MyDomain", null, info);
myAppDomain.ExecuteAssembly("AssemblyName.exe"); // load your assembly name
AppDomain.unload(myDomain);
}
}
上面代码创建了一个AppDomain的实例,并调用ExecuteAssembly方法加载一个程序集。其中AppDomainSetup为CLR定位信息。unload为AppDomain类的卸载域方法。注意:这段代码中ExecuteAssembly()方法的线程调用了AssemblyName.exe程序集的线程。这样一个线程就跨越了两个AppDomain。这也说明了AppDomain和线程之间没有包含关系。
到这里,我们已经对CLR中域的概念,各种域的结构有了一个大概的认识。AppDomain是CLR中最基本的概念,在CLR的整个框架中都与它有着千丝万缕的联系,掌握它是学习CLR的基础。有关AppDomain间通信的方法,我们在.NET Remoting篇中再详细阐述。