AppDomain是CLR的运行单元,它可以加载Assembly、创建对象以及执行程序。

AppDomain是CLR实现代码隔离的基本机制。
每一个AppDomain可以单独运行、停止;每个AppDomain有自己默认的异常处理;
一个AppDomain的运行失败不会影响到其他的AppDomain。
CLR在被CLR Host(windows shell or InternetExplorer or SQL Server)加载后,要创建一个默认的AppDomain,程序的入口点
(Main方法)就是在这个默认的AppDomain中执行。
1.AppDomain vs 进程
AppDomain被创建在进程中,一个进程内可以有多个AppDomain。一个AppDomain只能属于一个进程。
2.AppDomain vs 线程
其实两者本来没什么好对比的。AppDomain是个静态概念,只是限定了对象的边界;线程是个动态概念,它可以运行在不同的
AppDomain。
一个AppDomain内可以创建多个线程,但是不能限定这些线程只能在本AppDomain内执行代码。
CLR中的System.Threading.Thread对象其实是个soft thread,它并不能被操作系统识别;操作系统能识别的是hard thread。
一个soft thread只属于一个AppDomain,穿越AppDomain的是hard thread。当hard thread访问到某个AppDomain时,一个
AppDomain就会为之产生一个soft thread。
hard thread有thread local storage(TLS),这个存储区被CLR用来存储这个hard thread当前对应的AppDomain引用以及soft
thread引用。当一个hard thread穿越到另外一个AppDomain时,TLS中的这些引用也会改变。
当然这个说法很可能是和CLR的实现相关的。
3.AppDomain vs Assembly
Assembly是.Net程序的基本部署单元,它可以为CLR提供用于识别类型的元数据等等。Assembly不能单独执行,它必须被加载到
AppDomain中,然后由AppDomain创建程序集中的对象。
一个Assembly可以被多个AppDomain加载,一个AppDomain可以加载多个Assembly。
每个AppDomain引用到某个类型的时候需要把相应的assembly在各自的AppDomain中初始化。因此,每个AppDomain会单独保持一
个类的静态变量。
4.AppDomain vs 对象
任何对象只能属于一个AppDomain。AppDomain用来隔离对象,不同AppDomain之间的对象必须通过Proxy(reference type)或者
Clone(value type)通信。
引用类型需要继承System.MarshalByRefObject才能被Marshal/UnMarshal(Proxy)。
值类型需要设置Serializable属性才能被Marshal/UnMarshal(Clone)。
5.AppDomain vs Assembly Code
AppDomain和程序集的源代码是什么关系呢?每个程序集的代码会分别装载到各个AppDomain中?
首先我们要把程序集分3类
1.mscorlib,这是每个.net程序都要引用到的程序集。
2.GAC,这个是强命名的公用程序集,可以被所有的.net程序引用。
3.Assembly not in GAC,这是普通的assembly,可以不是强命名,不放到GAC中。
启动CLR,进入entry point时可以设置LoaderOptimization属性:
[LoaderOptimization(LoaderOptimization.MultiDomain]
static void Main()
{...}
LoaderOptimization属性可以设置三个不同的枚举值,来设置针对前面说的三种程序集的代码存放以及访问方式。
LoaderOptimization Enumeration/Attribute

Value Expected Domains in Process Each Domain Expected to Run ... Code for MSCORLIB Code for Assemblies in GAC Code for Assemblies not in GAC
SingleDomain One N/A Per-process Per-domain Per-domain
MultiDomain Many Same Program Per-process Per-process Per-process
MultiDomainHost Many Different Programs Per-process Per-process Per-domain

1.SingleDomain,由于只启动一个AppDomain,那么code就被直接装载到了AppDomain中,访问静态变量更快捷。

2.MultiDomain,所有的Assembly代码是进程级别的,因此所有的AppDomain只访问一份代码。这大大减少了程序占用的内存,但
是由于程序集的静态变量仍然在各个AppDomain中,因此代码访问静态变量需要先得到AppDomain的引用再进行转换,速度会受到
影响。
3.MultiDomainHost,只有GAC代码是共享的,非GAC的Assembly依然会加载到被使用的AppDomain中,这样提高了静态变量的访问
速度,当然也增加了程序占用的内存。 
 
不管是哪种方式,mscorlib始终是process级别的,即只有一份mscorlib代码在内存中。

C#中动态加载和卸载DLL

在C++中加载和卸载DLL是一件很容易的事,LoadLibrary和FreeLibrary让你能够轻易的在程序中加载DLL,然后在任何地方 卸载。在C#中我们也能使用Assembly.LoadFile实现动态加载DLL,但是当你试图卸载时,你会很惊讶的发现Assembly没有提供任何 卸载的方法。这是由于托管代码的自动垃圾回收机制会做这件事情,所以C#不提供释放资源的函数,一切由垃圾回收来做。

这引发了一个问题,用Assembly加载的DLL可能只在程序结束的时候才会被释放,这也意味着在程序运行期间无法更新被加载的DLL。而这个功能在某 些程序设计时是非常必要的,考虑你正在用反射机制写一个查看DLL中所有函数详细信息的程序,程序提供一个菜单让用户可以选择DLL文件,这时就需要让程 序能够卸载DLL,否则一旦用户重新得到新版本DLL时,必须要重新启动程序,重新选择加载DLL文件,这样的设计是用户无法忍受的。

C#也提供了实现动态卸载DLL的方法,通过AppDomain来实现。AppDomain是一个独立执行应用程序的环境,当AppDomain被卸载的 时候,在该环境中的所有资源也将被回收。关于AppDomain的详细资料参考MSDN。下面是使用AppDomain实现动态卸载DLL的代码,

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Threading; 
using System.Reflection; 
namespace UnloadDll 

class Program 

static void Main(string[] args) 

string callingDomainName = AppDomain.CurrentDomain.FriendlyName;//Thread.GetDomain().FriendlyName; 
Console.WriteLine(callingDomainName); 
AppDomain ad = AppDomain.CreateDomain("DLL Unload test"); 
ProxyObject obj = (ProxyObject)ad.CreateInstanceFromAndUnwrap(@"UnloadDll.exe", "UnloadDll.ProxyObject"); 
obj.LoadAssembly(); 
obj.Invoke("TestDll.Class1", "Test", "It's a test"); 
AppDomain.Unload(ad); 
obj = null; 
Console.ReadLine(); 


class ProxyObject : MarshalByRefObject 

Assembly assembly = null; 
public void LoadAssembly() 

assembly = Assembly.LoadFile(@"TestDLL.dll"); 

public bool Invoke(string fullClassName, string methodName, params Object[] args) 

if(assembly == null) 
return false; 
Type tp = assembly.GetType(fullClassName); 
if (tp == null) 
return false; 
MethodInfo method = tp.GetMethod(methodName); 
if (method == null) 
return false; 
Object obj = Activator.CreateInstance(tp); 
method.Invoke(obj, args); 
return true; 


}

注意:

1. 要想让一个对象能够穿过AppDomain边界,必须要继承MarshalByRefObject类,否则无法被其他AppDomain使用。

2. 每个线程都有一个默认的AppDomain,可以通过Thread.GetDomain()来得到

AppDomain 详解(转)的更多相关文章

  1. .Net AppDomain详解(二)

    AppDomain 类 表示应用程序域,它是一个应用程序在其中执行的独立环境. 此类不能被继承. 命名空间:   System程序集:  mscorlib(位于 mscorlib.dll) 继承层次结 ...

  2. C# AppDomain 详解

    AppDomain 详解 AppDomain是CLR的运行单元,它可以加载Assembly.创建对象以及执行程序. AppDomain是CLR实现代码隔离的基本机制.每一个AppDomain可以单独运 ...

  3. .Net AppDomain详解(一)

    AppDomain是CLR的运行单元,它可以加载Assembly.创建对象以及执行程序.AppDomain是CLR实现代码隔离的基本机制. 每一个AppDomain可以单独运行.停止:每个AppDom ...

  4. C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解

    前言:已经有一个月没写点什么了,感觉心里空落落的.今天再来篇干货,想要学习Webapi的园友们速速动起来,跟着博主一起来学习吧.之前分享过一篇 C#进阶系列——WebApi接口传参不再困惑:传参详解  ...

  5. App.Config详解及读写操作

    App.Config详解及读写操作   App.Config详解 应用程序配置文件是标准的 XML 文件,XML 标记和属性是区分大小写的.它是可以按需要更改的,开发人员可以使用配置文件来更改设置,而 ...

  6. 8天掌握EF的Code First开发系列之3 管理数据库创建,填充种子数据以及LINQ操作详解

    本文出自8天掌握EF的Code First开发系列,经过自己的实践整理出来. 本篇目录 管理数据库创建 管理数据库连接 管理数据库初始化 填充种子数据 LINQ to Entities详解 什么是LI ...

  7. log4net详解(转载)

    1.概述 log4net是.Net下一个非常优秀的开源日志记录组件.log4net记录日志的功能非常强大.它可以将日志分不同的等级,以不同的格式,输出到不同的媒介.本文主要是介绍如何在Visual S ...

  8. App.Config详解

    App.Config详解 应用程序配置文件是标准的 XML 文件,XML 标记和属性是区分大小写的.它是可以按需要更改的,开发人员可以使用配置文件来更改设置,而不必重编译应用程序.配置文件的根节点是c ...

  9. c# App.Config详解

    c# App.Config详解 应用程序配置文件是标准的 XML 文件,XML 标记和属性是区分大小写的.它是可以按需要更改的,开发人员可以使用配置文件来更改设置,而不必重编译应用程序. 配置文件的根 ...

随机推荐

  1. C#夯实基础之接口(《CLR via C#》读书笔记)

    一. 接口的类型 接口是引用类型.因此从值类型赋值给接口是需要装箱的.如下所示: class Program { static void Main(string[] args) { ISay catS ...

  2. DBCP连接池配置示例

    <bean id="dataSourceOracle2" class="org.apache.commons.dbcp.BasicDataSource" ...

  3. ajax——CORS跨域调用REST API 的常见问题以及前后端的设置

    RESTful架构是目前比较流行的一种互联网软件架构,在此架构之下的浏览器前端和手机端能共用后端接口. 但是涉及到js跨域调用接口总是很头疼,下边就跟着chrome的报错信息一起来解决一下. 假设:前 ...

  4. 设计模式--命令模式Command(对象行为型)

    一.命令模式 将一个请求封装为一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能. (1)Command类:是一个抽象类,类中对需要执行的命令进行 ...

  5. python正则表达式re

    Python正则表达式: re 正则表达式的元字符有. ^ $ * ? { [ ] | ( ).表示任意字符[]用来匹配一个指定的字符类别,所谓的字符类别就是你想匹配的一个字符集,对于字符集中的字符可 ...

  6. sqlserver添加主键

    sqlServer中给表添加主键的sql: alter table market_media_medical_history alter column pk_id bigint not null; a ...

  7. 自定义注解之运行时注解(RetentionPolicy.RUNTIME)

    对注解概念不了解的可以先看这个:Java注解基础概念总结 前面有提到注解按生命周期来划分可分为3类: 1.RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成clas ...

  8. 【mongo】mongoVUE使用

    1.查询存在字段"test"的项 {"test":{$exists:true}} 2.在表中插入字段 {$set:{"}} 3.正则匹配 {" ...

  9. HDU 1754 I Hate It 线段树单点更新求最大值

    题目链接 线段树入门题,线段树单点更新求最大值问题. #include <iostream> #include <cstdio> #include <cmath> ...

  10. WIN7凭据管理器保存的凭据过段时间会自动删除的解决办法

    控制面板\用户帐户和家庭安全\凭据管理器 进入该页面可看到所有凭据