C#基础 应用程序域AppDomain

一、AppDomain理解

为了保证代码的键壮性CLR希望不同服务功能的代码之间相互隔离,这种隔离可以通过创建多个进程来实现,但操作系统中创建进程是即耗时又耗费资源的一件事,所以在CLR中引入了AppDomain的概念,AppDomain主要是用来实现同一进程中的各AppDomain之间的隔离,AppDomain可以用以下特征来描述它的全貌:

  • AppDomain概念并不存在于操作系统,而只存在于.net中并且AppDomain不可脱离进程单独存在,它是属于某一CLR或寄宿着CLR的进程的。

  • 一个进程中可以有多个AppDomain,并且每个之间相互隔离(只保证安全代码的隔离,不安全代码并不能保证),此可以理解为AppDomain是.net程序中的"进程",在一个AppDomain中创建的对象只属于本AppDomain,多个AppDomain之间的对象不能相互访问,除非遵循CLR的一些规则。

  • .net程序启动时在进程中创建一个默认的AppDomain,入口代码将运行于此AppDomain,默认应用程序域只有在进程终止时才会被销毁,如果主动的调用Unload去卸载默认应用程序域,会抛出一个CannotUnloadAppDomainException。

  • 每个AppDomain都单独的加载程序集,这意味着在A应用程序域中加载了的程序集,并不一定在B应用程序域中也被加载了。每个APPDomain有单独的Loader堆,互相不影响,每个Loader堆都记录了自AppDomain建立以后所访问过的类型,Loader堆中的每个类型对象都有一个方法表,这些方法表指向已经被JIT编译过的本地代码(前提是这些方法是已经被至少执行过一次的)。因为AppDomain是相互隔离的所以相同的一个类型中的方法,在A应用程序域中是被JIT编译过的,但不一定在B应用程序域中也是被JIT编辑过的,方法是否被JIT编辑过取决于些方法是否在本AppDomain被调用过。

  • 当AppDomain被卸载时,此AppDomain中的程序集会被卸载,因为每个APPDomain加载的程序集都是独立的所以一个应用程序域被卸载并不会影响其它AppDomain中加载的程序集,另外本AppDomain的loader堆也会被回收,每个程序域的loader堆是独立的所以也不会影响到其它程序域的Loader堆,因为loader堆是独立的(静态字段是存在于类型对象上的),所以一个类型中的静态字段在不同应用程序域中也是不同的存在,所以静态字段也是不被影响的,唯一受影响的是线程,因为线程可以跨越应用程序域访问不同的应用程序域上的代码,后面我们会介绍当卸载一个应用程序域时如果对线程做处理。

  • 有一种程序集可以被多个AppDomain使用,这种程序集叫做"AppDomain中立"的程序集,比如MSCorLib.dll,该程序集包含了System.Object,System.Int32以及其它的与.net framework密不可分的类型,这个程序集在CLR初始化时会自动加载,JIT会为这些程序集创建一个特殊的Loader堆,并且程序集中的方法被编译成的本地代码可被所有AppDomain共享,这种程序集不可被卸载只有当进程结束时这种程序集才会被卸载。

官方解释:

AppDomain 类 (System) | Microsoft Learn

 二、C#中AppDomain.CurrentDomain.BaseDirectory及各种路径获取方法

string path = "";

//获取和设置当前目录(即该进程从中启动的目录)的完全限定路径。 结果:E:\项目\Test
path = Environment.CurrentDirectory;

// 获取程序的基目录。结果:E:\项目\Test\
path = System.AppDomain.CurrentDomain.BaseDirectory;

// 获取和设置当前目录(该进程从中启动的目录)的完全限定目录。 结果:E:\项目\Test
path = System.Environment.CurrentDirectory ;

// 获取应用程序的当前工作目录,注意工作目录是可以改变的,而不限定在程序所在目录。 结果:E:\项目\Test
path = System.IO.Directory.GetCurrentDirectory();

// 获取和设置包括该应用程序的目录的名称。 结果:E:\项目\Test\
path = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;

//获取项目下的Log文件路径 结果:E:\项目\Test\Log
path = System.Web.HttpContext.Current.Server.MapPath("~/Log");

我为什么会学到这个是因为实际中用到了AppDomain.CurrentDomain.BaseDirectory这个。然后搜索了一下网上的资料,发现我们平时用的最多的应该是AppDomain.CurrentDomain.BaseDirectory属性,它可以返回各种.NET项目的当前运行路径。

其次在ASP.NET Core项目中,我们有时候会用到Environment.CurrentDirectory,这个属性在ASP.NET Core项目发布前(在Visual Studio中运行ASP.NET Core项目)和发布后,返回的路径会有所不同。当ASP.NET Core项目发布后,AppDomain.CurrentDomain.BaseDirectory属性和Environment.CurrentDirectory属性会得到相同的文件夹。但在ASP.NET Core项目发布前(在Visual Studio中运行ASP.NET Core项目),AppDomain.CurrentDomain.BaseDirectory属性和Environment.CurrentDirectory属性会得到不同的文件夹路径。

三、Application.StartupPath和AppDomain.CurrentDomain.BaseDirectory的区别

Application.StartupPath只能用于WinForm窗体中,而AppDomain.CurrentDomain.BaseDirectory既可以用于WinForm窗体中,也可以用于类库DLL文件中。出处

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值