`
北极的。鱼
  • 浏览: 159285 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

应用程序域(Application Domain)

 
阅读更多

转载:http://www.360doc.com/content/09/0512/16/74246_3471947.shtml

大家都知道,.net写的程序,都是托管的,何为托管?就是让“其他的程序”来管理,也解析运行,什么又在这里充当“其他程序”呢?这里大体上说是CLR(通用语言运行时),这只是大体上的,准确的在底层是怎么去处理托管程序与操作系统间的关系呢? 操作系统上运行的都是进程,这进程是非托管的。现在。我们有一个Demo.exe,他是用.net写的(这里与语言无关了,因为编设成程序集后,都成为IL语言了),当然是一个托管理程序。这里的问题就是怎么把Demo.exe变成一个进程,运行在操作系统的进程中。这里就引出了应用程序域(Application Domain),应用程序域(Application Domain)是“托管理代码与非托管理代码之间的桥梁”(引自《.NET组件编程设计》),进程,应用程序域,.net程序集(这里是Demo.exe),之间的关系可以见下图:

 

一个进程中可以有多个应用程序域(Application Domain),一个应用程序域(Application Domain)中可以有多个程序集。

 

应用程序域(Application Domain)的引入的好处在于,如果一个程序集出现错误,不会影响到别的应用程序域(Application Domain),同时他们又是一个进程中的。

.net中,应用程序域(Application Domain)是用AppDomain类来表示的。

AppDomain CurrentAD=AppDomain.CurrentDomain;

上面的代码实现了获取当有程序集所在的应用程序域(Application Domain)。获取当前应用程序域(Application Domain)还可以通过当前线程来得到,如下:

AppDomain CurrentAD=Threed.GetDomain();

下面再看一下在当前应用程序域(Application Domain)中创建对象:

类:

Class Class1
{
    Public void FF()
    {
       //实现功能
    }
}

AppDomain CurrentAD=Threed.GetDomain();

Class1 C1=(Class1)CurrentAD.CreateInstanceAndUnwrap(程序集名称,名命空间.类名);

C1.FF();

这个是关于当前的应用程序域(Application Domain)的操作,怎么创建一个应用程序域(Application Domain)呢?看下面

AppDomain MyAppDomain=AppDomain.CreatDomain(MyNewAD);

Class1 C1=(Class1)MyAppDomain.CreateInstanceAndUnwrap(程序集名称,名命空间.类名);

C1.FF();

AppDomain MyAppDomain=AppDomain.CreatDomain(MyNewAD);

IObjectHandle handle=MyAppDomain.CreateInstance 程序集名称,名命空间.类名);

Class1 C1=(Class1)handle.Unwrap();

C1.FF();

后都的好处在于用C1这个对象的时候才进处理。
 
我们知道,进程是操作系统用于隔离众多正在运行的应用程序的机制。在.Net之前,每一个应用程序被加载到单独的进程中,并为该进程指定私有的虚拟内存。进程不能直接访问物理内存,操作系统通过其它的处理把这些虚拟内存映射到物理内存或IO设备的某个区域,而这些物理内存之间不会有重叠,这就决定了一个进程不可能访问分配给另一个进程的内存。相应地,运行在该进程中的应用程序也不可能写入另一个应用程序的内存,这确保了任何执行出错的代码不会损害其地址空间以外的应用程序。在这种机制下,进程作为应用程序之间一个独立而安全的边界在很大程度上提高了运行安全。

进程的缺点是降低了性能。许多一起工作的进程需要相互通信,而进程却不能共享任何内存,你不能通过任何有意义的方式使用从一个进程传递到另一个进程的内存指针。此外,你不能在两个进程间进行直接调用。你必须代之以使用代理,它提供一定程度的间接性。虽然,使用动态连接库dll让所有的组件运行在同一空间,一定程度上可以提高性能,但这些组件相互影响,一个组件的错误将极有可能导致整个应用程序的崩溃,“dll地狱”更是让许多应用程序难以避免。

 

应用程序域(AppDomain)

在.Net中,应用程序有了一个新的边界:应用程序域(以下简称域)。它是一个用于隔离应用程序的虚拟边界。为了禁止不应交互的代码进行交互,这种隔离是必要的。.Net的应用程序在域层次上进行隔离,一个域中的应用程序不能直接访问另一个域中的代码和数据。这种隔离使得在一个应用程序范围内创建的所有对象都在一个域内创建,确保在同一进程中一个域内运行的代码不会影响其他域内的应用程序,大大提高了运行的安全。

.Net结构中,由于公共语言运行库能够验证代码是否为类型安全的代码,所以它可以提供与进程边界一样大的隔离级别,其性能开销也要低得多。你可以在单个进程中运行几个域,而不会造成进程间调用或切换等方面的额外开销。这种方法是把任何一个进程分解到多个域中,允许多个应用程序在同一进程中运行,每个域大致对应一个应用程序,运行的每个线程都在一个特殊的域中。如果不同的可执行文件都运行在同一个进程空间中,它们就能轻松地共享数据或直接访问彼此的数据。这种代码同运行同一个进程但域不同的类型安全代码一起运行时是安全的。在一个进程内运行多个应用程序的能力显著增强了服务器的可伸缩性。

域间通信

域是.Net 带来的一个重要改进,它不仅将众多在运行的应用程序隔离开来,还不影响彼此间通信。虽然,公共语言运行库禁止在不同域中的对象之间进行直接调用,但我们可以复制这些对象,或通过代理访问这些对象。如果以前一种方式,那么对该对象的调用为本地调用。也就是说,调用方和被引用的对象位于同一域中。如果通过代理访问对象,调用方和被引用的对象位于不同的域中,对该对象的调用被视为远程调用,这种情形与两个进程间的调用或两台计算机间的调用结构大致相同。这时,需要被引用对象的元数据对于两个域均可用,以便.Net即时编译JIT能正确执行。

域与线程的关系

在.Net中,线程是公共语言运行库用来执行代码的操作系统构造。在运行时,所有托管代码均加载到一个域中,由特定的操作系统线程来运行。然而,域和线程之间并不具有一一对应关系。在任意给定时间,单个域中可以执行不止一个线程,而且特定线程也并不局限在单个域内。也就是说,线程可以跨越域边界,不为每个域创建新线程。当然,在指定时刻,每一线程都只能在一个域中执行。运行库会跟踪所有域中有哪些线程正在运行。通过调用.Net类库的 Thread.GetDomain 方法,你还可以确定正在执行的线程所在的域。

 

域的创建

作为公共语言运行库的隔离单元,域在进程中创建和运行。.Net结构中,运行时宿主(也叫作运行时主机)是负责将运行时载入进程并在域中执行用户代码和托管代码的应用程序。运行时宿主包括ASP.Net、浏览器Internet Explorer 和 Windows等外壳程序,负责创建进程和默认域,例如,Asp.Net为每个运行在web服务器上的web应用程序创建一个域。浏览器Internet explore创建运行受管制控件的域。

对多数应用程序,你并不必须创建相应的域,每次CLR在初始化一个进程时,将创建默认域,并使该进程运行于这个默认域下。然而,默认域不能由任何系统调用来卸载,该域只有在进程被卸载之后才能被销毁。如果直接在默认域下编程或运行代码,而由于某种原因域的代码崩溃了,那么就有使得整个服务随之崩溃的风险。

于是,针对不同的应用程序,应该创建和配置相应的域并载入适当的程序集。.Net为此提供了丰富的类库。其中,AppDomain 类是域的编程接口,其大量的(重载)方法能完成以下任务:

· 创建域

· 在域中加载程序集和类型

· 枚举域中的程序集和线程

· 卸载域

创建新域时,使用AppDomain 类的静态方法CreateDomain。你可以为域命名并按该名称来引用域。下面的示例语句创建新域,并为它指定名称 MyDomain:

     AppDomain myDomain = AppDomain.CreateDomain("MyDomain");

 然后你可以查询当前域的名称和新创建子域的名称:

     string hostDomain=AppDomain.CurrentDomain.FriendlyName;
     string childDomain=myDomain.FriendlyName;

 在这里,属性FriendlyName表示的是域的友好名称,友好名称通过从程序集的基本代码中去除目录路径而形成。例如,文件名为 "d:\MyAppDomain\MyAssembly.exe" 的程序集加载到默认域中,域的友好名称就是 "MyAssembly.exe"。

更一般的是,在创建域之前,先设置好域的参数,这可以通过类AppDomainSetup来完成。该类的ApplicationBase 属性定义应用程序的根目录, AppDomainSetup 类还有一个极重要的属性变量LoaderOptimizzation,取值可以是MultiDomain,MultiDomainHost和SignleDomain等,用以指定被加载程序集的类别(共享程序集或域专用程序集),例如,以下语句把程序集设置为域专用程序集:

     appDomainSetup.LoaderOptimization=LoaderOptimizatiion.SigleDomain;

 对以上两个方面简单归纳一下,对域的典型操作就包括:设置参数然后创建两个步骤,语句示例如下:

     AppDomainSetup appDomainSetup=new AppDomainSetup();//实例化域设置
     appDomainSetup.LoaderOptimization=LoaderOptimization.SingleDomain; //指定域类别
     AppDoman ad=AppDomain.CreateDomain(domainName,appDomainSetup); //创建域
     ...
     //应用程序在这里运行代码
     ...
     AppDomain.Unload(ad);//卸载域

 卸载域

当使用完域时,可使用AppDomain类Unload()静态方法将其卸载。要卸载进程中在运行的托管代码,只能卸载代码运行时所在的域而不能卸载单独的程序集或类型,Unload方法会正常关闭指定的域。这时,载入域的所有程序集都会被移除,并且无法再使用。不过,如果域中的程序集对域是非特定的(域无关程序集,也即共享程序集),则程序集的数据还会保留在内存中,直至整个进程关闭。除了关闭整个进程,没有机制可以卸载这类程序集。由于一个进程中允许包含多个域,某个域可以在不停止整个进程的情况下卸载。以这样的方式卸载不再需要的代码,可以减少内存占用并极大提高应用程序的可缩放性。此外,由于线程并不与域一一对应,当域中存在活动线程时,调用AppDomain.Unload方法可能无法将域卸载并导致异常。

 

在域中加载程序集

从上面的论述不难看出:要运行应用程序,必须首先将程序集(.Net下经编译产生,包含IL中间语言、元数据及清单等)加载到域中。而且一个域中可装载多个程序集。默认情况下,公共语言运行库自动将一个程序集加载到包含引用该程序集的代码的域。通过此方法,该程序集的代码和数据独立于使用该程序集的应用程序。

自行创建域的好处之一便是可以指定如何装载程序集。在域中有以下两种方式加载程序集:

1、将当前程序集加载入单独的域中,同一个程序集可能有多个副本;

2、以非特定于域的形式加载程序集,让一个程序集在多个域间共享;

这两种方式各自偏重于安全性和性能,需要视具体情况在二者之间权衡。具体地,在 .Net 框架中,System.Reflection.Assembly 类提供以下静态方法将程序集加载至域:

· Load()在给顶程序集名称的前提下,加载该程序集:

    Assembly SampleAssembly;
    …
    SampleAssembly = Assembly.Load("System.Data");//根据类型加载程序集

 LoadFrom()在已知程序集文件名或路径等信息的情况下加载程序集:

Assembly SampleAssembly;
    …
    SampleAssembly = Assembly.LoadFrom("c:\\Sample.Assembly.dll");//根据已有程序集名

 

1、appDomain是.NET框架独有的概念。找不到其他技术体系中贴切的参照概念,是微软自己的东东。很多人认为可以同进程的概念相同,我很不赞同:其一,“进程”是操作系统中的概念,在虚拟机/框架之类的体系中有着自己的定义和功能,显然这样理解appDomain是错误的;其二,“在应用程序域和线程之间没有一对一的关联,多个线程可以属于一个应用程序域,尽管给定的线程并不局限于一个应用程序域,但在任何给定时间,线程都在一个应用程序域中执行。”(.NET FrameWork SDK 中的描述),如果这里的“应用程序域”换成“进程”讲得通么?

2、隔离性。也不怪有人直接套解为进程,AppDomain有着代码执行隔绝的特性,就好像进程做的一样。appDomain的对象、代码可以认为相互隔离,甚至一个appDomain中的代码调用另外appDomain的对象(的数据或者方法等),需要类似DCOM中的“列集/散集”才可以进行(在类继承关系中appDomain类 继承自 MarshalByRefObject类)。每一个appDomain可以单独被调试、启动、停止,有着自己的默认的异常处理,一个appDomain崩溃了,不会影响其他的appDomain。可以理解为.NET的“逻辑进程”。

.NET中允许同一个应用程序的不同版本可以并存,消除了所谓的“dll hell”。通过创建不同的appDomain,我们可以让某个托管的程序集的1.0和2.0的版本同时执行(只要他们自身并不存在某个特定资源的非兼容性的存取访问)

       3、安全性。由于代码隔离,可以防止某个危险代码对于其他的appDomain的影响。而且可以通过分配特定的安全分配,确定appDomain中的执行代码对于系统安全保护资源的访问。

       4、独立性。每一个appDomain都由.NET的框架分配了专用的存储区(应用域局部存储)。任何对象都可以访问自己当前所在的appDomain的局部存储区,这个局部存储区被整个appDomain中的对象共享,也包括进入appDomain的线程(运行于同一个appDomain的线程可以通过这个局部存储进行通信)。

 

       5、同进程、线程、程序集的关系。同进程属于多对一的关系,即一个进程中可以有多个appDomain,但是appDomain只能存在于某个进程中(显然,正如同上文:进程同appDomain属于不同的概念)。缺省情况下,如果你没有自己创建多个appDomain,一个进程启动后自动创建一个appDomain。而线程执行可以涉及多个appDomain,但某个特定时刻,线程仅存在于一个appDomain中,且线程可以进入其他的appDomain。某个程序集的某个实例属于具体的appDomain,由appDomain在自己的范围内加载,并按照程序集创建相应的对象。AppDomain是程序集的执行环境,同时程序集作为静态实体,可以被多个appDomain加载执行。

 

 

++++++++++++++++++++++++

所以说,是出于2个主要原因引入AppDomain的:

1. 安全性:要保证域之间不会随意调用对象,即不会对出现A域中的程序调用B中的对象(正常情况下), 也不会出现,因为一个域出错而且导致其他的域都出错。

2. 性能:相对于进程的性能开销太大,CLR的开销就理想多了。

  • 大小: 11.2 KB
分享到:
评论

相关推荐

    详解flash应用程序域

    `LoaderContext`对象的`applicationDomain`属性允许开发者控制子SWF加载时应用程序域的放置方式。通过使用`ApplicationDomain.currentDomain`或新建`ApplicationDomain`实例,开发者可以灵活地决定子SWF的定义应当...

    深入理解ApplicationDomain和SecurityDomain

    #### 安全域(Security Domain)与应用程序域(Application Domain)概述 安全域与应用程序域是Flash Player中两种重要的沙箱概念,它们帮助开发者理解如何管理和隔离不同来源的内容。这篇文章将详细介绍这两个概念...

    详细介绍ApplicationDomain和SecurityDomain

    当加载一个新类时,Flash Player会先检查当前的应用程序域是否有这个类,如果没有,则会向上级应用程序域查找。 **3. 示例** ```as3 var parentAppDomain:ApplicationDomain = ApplicationDomain.currentDomain; ...

    ApplicationDomain的误解,安全沙箱有关内容

    ### ApplicationDomain的理解与安全沙箱相关知识 ...通过上述介绍,我们可以看到`ApplicationDomain`在AS3编程中的重要性,它不仅有助于构建更加安全的应用程序,还为开发复杂的RIA应用提供了强大的支持。

    applicationDomain学习资料

    通过合理利用运行时共享库资源和创作时共享库资源,开发者可以构建更加高效、灵活且易于维护的应用程序和游戏。掌握这一技术不仅可以提高开发效率,还能优化用户体验,特别是在资源密集型的多媒体项目中。因此,深入...

    Flex ApplicationDomain

    ApplicationDomain,可以翻译为“应用程序域”,是ActionScript 3中的一个核心组件,用于管理和隔离不同的代码资源,确保它们在运行时能够独立运作而不会相互干扰。 首先,我们要明白,ActionScript 3中的每个运行...

    NET remoting 技术 -1

    1. **应用程序域(Application Domain)** - 应用程序域是.NET框架中的一种隔离机制,用于在单一进程中创建多个相互隔离的运行环境。这使得可以在同一进程中运行不同的应用程序而彼此之间互不影响。 - 每个.NET...

    计算机专业词汇.txt

    app domain (application domain)应用域 application 应用、应用程序 application framework 应用程序框架 appearance 外观 append 附加 architecture 架构、体系结构 archive file 归档文件、存档文件 argument引数...

    java基于UNIX域套接字(unix domain socket)连接redis

    为了优化网络通信,有时我们会选择使用UNIX域套接字(UNIX Domain Socket,简称UDS)来代替传统的TCP/IP套接字进行进程间通信(IPC)。本篇将详细讲解如何在Java环境下,利用UNIX域套接字连接并操作Redis,以及涉及...

    如何在c#程序中模拟域帐户进行登录操作

    该函数允许应用程序以指定的用户身份登录到一个系统。如果登录成功,则会返回一个令牌,该令牌可以用来代表登录的用户执行后续操作。 #### 代码实现 下面是一个简单的C#代码示例,展示了如何使用`LogonUser`函数...

    weblogic9.2应用程序部署

    WebLogic Server 9.2 是 Oracle 公司提供的一个企业级 Java 应用服务器,它提供了用于开发、部署和管理Java EE(Java Platform, Enterprise Edition)应用程序的平台。本篇文章将详细阐述在WebLogic 9.2上进行应用...

    Sun Java System Application Server Enterprise Edition 8.2 管理指南.pdf

    Application Server 是一种中间件平台,用于托管企业应用程序,例如Web应用和EJBs等。它为开发人员提供了一个运行时环境,可以在此环境中部署、管理和执行应用程序组件。 **2. Application Server 体系结构** Sun ...

    简单了解WebLogic Cluster的配置与应用程序

    ### WebLogic Cluster配置与应用程序发布详解 #### 一、引言 随着企业级应用的不断发展,高可用性和负载均衡成为了IT系统设计中的关键需求之一。WebLogic Server作为一款功能强大的应用服务器,通过集群(Cluster)...

    C#获取运行程序路径

    然而,这里通过`Thread.GetDomain()`获取当前线程所属的应用程序域,这在多线程环境中可能会有所差异。 #### 10. 获取正在执行的程序集的位置 ```csharp string str10 = System.Reflection.Assembly....

    C#获取程序运行路径的几种方式

    4. **System.Threading.Thread.GetDomain().BaseDirectory**: 同上,返回当前应用程序域的基础目录。 ```csharp string path = System.Threading.Thread.GetDomain().BaseDirectory; ``` 5. **Environment....

    Application Server管理配 置

    - 部署应用程序:使用`asadmin deploy`命令部署应用程序。 - 创建新的资源类型:使用`asadmin create-resource`命令定义新的资源类型。 - Administration Server 高级设置:通过`asadmin set-property`命令进行更...

Global site tag (gtag.js) - Google Analytics