AppDomain是一组程序集的逻辑容器, AppDomain唯一的作用就是进行隔离, 是.Net中独有的. 创建一个托管应用程序同时会创建一个默认AppDomain
AppDomain具体功能
1.一个AppDomain中的代码创建的对象不能由另一个AppDomain中的代码直接访问
如果需要访问,则需要通过代理的形式, 即使用"按引用封发" 和"按值封发"
2. AppDomain可以卸载
CLR不支持从一个AppDomain卸载程序集,但是可以卸载AppDomain, 卸载AppDomain的同时,AppDomain中分配的所有资源一并释放
3. AppDomain可以单独保护
创建AppDomain的同时,可以分配一个权限
4.. AppDomain可以单独配置
在创建AppDomain的同时,亦可以独立设置配置
创建AppDomain
//参数说明: 1: 应用程序域名 2: 权限 3:配置 传null则表示按当前AppDomain配置
AppDomain appDomain = AppDomain.CreateDomain("应用程序域名", null, null);
跨AppDomain访问对象
跨AppDomain访问对象有3种行为, "按引用封送" , "按值封送", "不能封送"
首先构造3个类,即按 " 按应用封送" , "按值封送", "不能封送" ,注意, 如何封送,或者说能不能封送, 是有这个类型自己决定的
//按应用封送
publicclass MarshlaByRefType : MarshalByRefObject
{
publicvoid DoSomthing()
{
//.....
}
}
//按值封送
[Serializable]
publicclass MarshalByValType : Object
{
publicvoid DoSomthing()
{
//.....
}
}
//不能封送
publicclass NonMarshalableType : Object
{
publicvoid DoSomthing()
{
//.....
}
}
调用:
//通过线程,可以获取当前AppDomain
AppDomain currAppDomain = System.Threading.Thread.GetDomain();
//输出当前AppDomain 名称,FriendlyName 是只读的,只有创建是才可以赋值, 默认AppDomain名称为应用程序名
Console.WriteLine(currAppDomain.FriendlyName);
//获取当前程序集名称
string exeAssemble = Assembly.GetEntryAssembly().FullName;
按引用封送
//按应用封送
AppDomain refAppDomain = AppDomain.CreateDomain("RefAddDomain", null, null);
MarshalByRefType marshalRefType = (MarshalByRefType)refAppDomain.CreateInstanceAndUnwrap(exeAssemble, "MarshalByRefType");
/*
* 顺利执行
* 当代码执行到此处时, 线程会切换到refAppDomain的应用程序与中,执行真实的DoSomthring()
* 此处的refAppDomain 只不过是一个代理引用
*/
marshalRefType.DoSomthing();
//调用IsTransparentProxy判断是否为代理 Result: true
Console.WriteLine("Is Proxy={0}", RemotingServices.IsTransparentProxy(refAppDomain));
按值封送
//按值封送
AppDomain valAppDomain = AppDomain.CreateDomain("RefAddDomain", null, null);
MarshalByValType marshalValType = (MarshalByValType)valAppDomain.CreateInstanceAndUnwrap(exeAssemble, "MarshalByValType");
/*
* 顺利执行
* 代码执行到此处时,实际调用的是当前AppDomain marshalValType的DoSomthing()方法
* 因为MarshalByValType标记了Serializable特性
*/
marshalRefType.DoSomthing();
//调用IsTransparentProxy判断是否为代理 Result: false
Console.WriteLine("Is Proxy={0}", RemotingServices.IsTransparentProxy(marshalValType));
不能封送
//不能封送
AppDomain nonAppDomain = AppDomain.CreateDomain("RefAddDomain", null, null);
NonMarshalableType marshalNonType = (NonMarshalableType)nonAppDomain.CreateInstanceAndUnwrap(exeAssemble, "NonMarshalableType");
/*
* 此处异常
*/
marshalRefType.DoSomthing();
监视AppDomain
设置AppDomain的MonitoringEnabled属性为true, 启用监视. 设置为true后,无法设置为false,即启用监视后不能关闭
启用监视后, 可以通过下面四个只读属性查看AppDomain运行相关参数
AppDomain.MonitoringIsEnabled =true;
//所有AppDomain使用字节数
AppDomain.MonitoringSurvivedProcessMemorySize;
//当前正在使用的字节数
nonAppDomain.MonitoringSurvivedMemorySize;
//此AppDomain分配的直接数
nonAppDomain.MonitoringTotalAllocatedMemorySize;
//CPU占用率
nonAppDomain.MonitoringTotalProcessorTime;
AppDomain FirstChance 异常通知
通过设置FirstChanceException事件 ,可以获取AppDomain异常,但是无法终止, 当AppDomain遇到异常时,会向上查找Catch快,如果没有找到,则会继续向上抛,知道遇到捕获快为止,反之程序异常终止
注意:
不同的AppDomain引用System.dll时, 每个AppDomain都会创建的自己的内存区域,也就是说AppDomain之见毫不相干,各干各得, 虽然这是一种浪费,但是为了保证隔离性,这是必须的, 同时卸载AppDomain时,也不会影响其他AppDomain.