AppDomain一——基本原理

2023-11-19

一、问题的提出

技术一定是为了解决某个应用场景的问题而产生的。很多时候,我们都想使用(开发)USB式(热插拔)的应用,例如,开发一个WinForm应用,并且这个WinForm应用能允许开发人员定制扩展插件,我们不能关闭程序。在把新的dll替换旧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介绍

应用程序域:(Application Domain,简称App Domain)。

以前,每个应用程序都在自己的进程地址空间中运行,由于进程之间是无法直接调用的,这可以保证应用程序的相互隔离,可以防止安全漏洞、数据破坏和其他不可预测的行为,确保应用程序的健壮性。但是在windows中创建进程的开销很大(Win32的CreateProcess函数的速度很慢,而且windows系统需要大量内存来虚拟化一个进程的地址空间),并且如果要在进程间相互通信是十分麻烦的。

,在.Net以前,每个程序是"封装"在不同的进程中的,这样导致的结果就造就占用资源大,可复用性低等缺点.而AppDomain在同一个进程内划分出多个"域",一个进程可以运行多个应用,提高了资源的复用性,数据通信等.详见应用程序域

CLR在启动的时候会创建系统域(System Domain),共享域(Shared Domain)和默认域(Default Domain),系统域与共享域对于用户是不可见的,默认域也可以说是当前域,它承载了当前应用程序的各类信息(堆栈),所以,我们的一切操作都是在这个默认域上进行."插件式"开发很大程度上就是依靠AppDomain来进行.

具体功能:

  • 隔离,一个AppDomain中的代码创建的对象不能由另一个AppDomain中的代码直接访问。达到隔离应用程序的效果。当然如果要访问别的AppDomain中的内容,可以使用“按引用问封送”或者“按值封送”的语义。    

  • AppDomain可以卸载,但不能卸载单独的程序集或类型,只能卸载整个应用程序域。从而卸载包含在该AppDomain中的所有程序集。

  • AppDomain可以单独保护,AppDomain在创建后,会应用一答个权限集,它决定了向这个AppDomain中运行的程序集授予的最大权限。从而保护宿主加载的代码不被破坏。

  • 可以单独实施配置,AppDomain在创建后,会关回联一组配置设置。这些设置主要影响CLR在AppDomain中加载程序集的方式。这些设置涉及搜索路答径、版本重定向、卷影复制以及加载器优化。

三、实例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleAppTest
{

    class Program
    {
        static void Main(string[] args)
        {


            // Get and display the friendly name of the default AppDomain.
            string callingDomainName = Thread.GetDomain().FriendlyName;//对于默认应用程序域,友好名称是应用程序的可执行文件的名称。
            Console.WriteLine(callingDomainName);

            // Get and display the full name of the EXE assembly.
            string exeAssembly = Assembly.GetEntryAssembly().FullName;
            Console.WriteLine(exeAssembly);
            Console.WriteLine("程序集的名称获取完成!");
            Console.WriteLine();

            // Construct and initialize settings for a second AppDomain.
            AppDomainSetup ads = new AppDomainSetup();
            ads.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
            ads.DisallowBindingRedirects = false;
            ads.DisallowCodeDownload = true;
            ads.ConfigurationFile =
                AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;

            // Create the second AppDomain.
            AppDomain ad2 = AppDomain.CreateDomain("SecondDomain", null, ads);

            // Create an instance of MarshalbyRefType in the second AppDomain. 
            // A proxy to the object is returned.
            MarshalByRefType mbrt =
                (MarshalByRefType)ad2.CreateInstanceAndUnwrap(
                    exeAssembly,
                    typeof(MarshalByRefType).FullName
                );

            // Call a method on the object via the proxy, passing the 
            // default AppDomain's friendly name in as a parameter.
            mbrt.SomeMethod(callingDomainName);

            // Unload the second AppDomain. This deletes its object and 
            // invalidates the proxy object.

           // AppDomain.Unload(ad2);//卸载了第二个域,所以会失败,执行catch
            try
            {
                // Call the method again. Note that this time it fails 
                // because the second AppDomain was unloaded.
                mbrt.SomeMethod(callingDomainName);
                Console.WriteLine("Sucessful call.");
            }
            catch (AppDomainUnloadedException)
            {
                Console.WriteLine("Failed call; this is expected.");
            }
            Console.ReadKey();
        }


    }

    // Because this class is derived from MarshalByRefObject, a proxy
    // to a MarshalByRefType object can be returned across an AppDomain 
    // boundary.
    public class MarshalByRefType : MarshalByRefObject
    {
        //  Call this method via a proxy.
        public void SomeMethod(string callingDomainName)
        {
            // Get this AppDomain's settings and display some of them.
            AppDomainSetup ads = AppDomain.CurrentDomain.SetupInformation;
            Console.WriteLine("AppName={0}, AppBase={1}, ConfigFile={2}",
                ads.ApplicationName,
                ads.ApplicationBase,
                ads.ConfigurationFile
            );
            Console.WriteLine();
    

            // Display the name of the calling AppDomain and the name 
            // of the second domain.
            // NOTE: The application's thread has transitioned between 
            // AppDomains.
            Console.WriteLine("Calling from '{0}' to '{1}'.",
                callingDomainName,
                Thread.GetDomain().FriendlyName
            );
        }
    }
}




参考:

https://www.cnblogs.com/rgshare/archive/2013/06/03/3115324.html

https://blog.csdn.net/talent_jian/article/details/54837064

https://blog.csdn.net/cui6864520fei000/article/details/86225421

https://docs.microsoft.com/zh-cn/dotnet/api/system.appdomain?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev15.query%3FappId%3DDev15IDEF1%26l%3DZH-CN%26k%3Dk(System.AppDomain);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5);k(DevLang-csharp)%26rd%3Dtrue&view=netframework-4.8

 

 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

AppDomain一——基本原理 的相关文章

  • 无法使用 strptime() 获取秒数

    我收到 YYYY MM DDThh mm ss S Z hh mm 这种格式的日期时间 我正在尝试使用复制该值strptime如下所示 struct tm time 0 char pEnd strptime datetime Y m dT
  • boost::multi_index_container 复合键中的 equal_range 与比较运算符

    我正在尝试从多索引容器查询结果 其中值类型是三个元素的结构 第一个值已给出 但第二个和第三个值必须大于或小于查询参数 经过搜索后 我发现必须实现自定义密钥提取器 并且这里的一些链接建议相同 但我无法实现它 boost multi index
  • 在 LINQ 查询中返回不带时间的日期

    我正在编写一个查询 我想计算按日期联系我们的呼叫中心的次数 看起来很简单 但由于联系日期字段是日期时间字段 我得到了时间 因此当我按联系日期 时间 分组时 每个联系日期实例的计数为 1 所以 我想只按日期分组 而不按时间分组 下面是我用来查
  • 属性对象什么时候创建?

    由于属性实际上只是附加到程序集的元数据 这是否意味着属性对象仅根据请求创建 例如当您调用 GetCustomAttributes 时 或者它们是在创建对象时创建的 或者 前两个的组合 在由于 CLR 的属性扫描而创建对象时创建 从 CLR
  • Signalr 在生产服务器中总是陷入长轮询

    当我在服务器中托管应用程序时 它会检查服务器端事件并始终回退到长轮询 服务器托管环境为Windows Server 2012 R1和IIS 7 5 无论如何 我们是否可以解决这个问题 https cloud githubuserconten
  • Func 方法参数的首选命名约定是什么?

    我承认这个问题是主观的 但我对社区的观点感兴趣 我有一个缓存类 它采用类型的缓存加载器函数Func
  • 模板类的不明确多重继承

    我有一个真实的情况 可以总结为以下示例 template lt typename ListenerType gt struct Notifier void add listener ListenerType struct TimeListe
  • C# 中值类型和引用类型有什么区别? [复制]

    这个问题在这里已经有答案了 我知道一些差异 值类型存储在堆栈上 而引用类型存储在托管堆上 值类型变量直接包含它们的值 而引用变量仅包含对托管堆上创建的对象位置的引用 我错过了任何其他区别吗 如果是的话 它们是什么 请阅读 堆栈是一个实现细节
  • 将字符串从非托管代码传递到托管

    我在将字符串从非托管代码传递到托管代码时遇到问题 在我的非托管类中 非托管类 cpp 我有一个来自托管代码的函数指针 TESTCALLBACK FUNCTION testCbFunc TESTCALLBACK FUNCTION 接受一个字符
  • 使用 C# 在 WinRT 中获取可用磁盘空间

    DllImport kernel32 dll SetLastError true static extern bool GetDiskFreeSpaceEx string lpDirectoryName out ulong lpFreeBy
  • 如何针对 Nancy 中的 Active Directory 进行身份验证?

    这是一篇过时的文章 但是http msdn microsoft com en us library ff650308 aspx paght000026 step3 http msdn microsoft com en us library
  • 初始化变量的不同方式

    在 C 中初始化变量有多种方法 int z 3 与 int 相同z 3 Is int z z 3 same as int z z 3 您可以使用 int z z 3 Or just int z 3 Or int z 3 Or int z i
  • 网络参考共享类

    我用 Java 编写了一些 SOAP Web 服务 在 JBoss 5 1 上运行 其中两个共享一个类 AddressTO Web 服务在我的 ApplycationServer 上正确部署 一切都很顺利 直到我尝试在我的 C 客户端中使用
  • 可空属性与可空局部变量

    我对以下行为感到困惑Nullable types class TestClass public int value 0 TestClass test new TestClass Now Nullable GetUnderlyingType
  • 什么是 C 语言的高效工作流程? - Makefile + bash脚本

    我正在开发我的第一个项目 该项目将跨越多个 C 文件 对于我的前几个练习程序 我只是在中编写了我的代码main c并使用编译gcc main c o main 当我学习时 这对我有用 现在 我正在独自开展一个更大的项目 我想继续自己进行编译
  • 在 ASP.NET 中将事件冒泡为父级

    我已经说过 ASP NET 中的层次结构 page user control 1 user control 2 control 3 我想要做的是 当控件 3 它可以是任何类型的控件 我一般都想这样做 让用户用它做一些触发回发的事情时 它会向
  • 如何使用 ReactiveList 以便在添加新项目时更新 UI

    我正在创建一个带有列表的 Xamarin Forms 应用程序 itemSource 是一个reactiveList 但是 向列表添加新项目不会更新 UI 这样做的正确方法是什么 列表定义 listView new ListView var
  • C++ 成员函数中的“if (!this)”有多糟糕?

    如果我遇到旧代码if this return 在应用程序中 这种风险有多严重 它是一个危险的定时炸弹 需要立即在应用程序范围内进行搜索和销毁工作 还是更像是一种可以悄悄留在原处的代码气味 我不打算writing当然 执行此操作的代码 相反
  • 为什么 strtok 会导致分段错误?

    为什么下面的代码给出了Seg 最后一行有问题吗 char m ReadName printf nRead String s n m Writes OK char token token strtok m 如前所述 读取字符串打印没有问题 但
  • 不同类型的指针可以互相分配吗?

    考虑到 T1 p1 T2 p2 我们可以将 p1 分配给 p2 或反之亦然吗 如果是这样 是否可以不使用强制转换来完成 或者我们必须使用强制转换 首先 让我们考虑不进行强制转换的分配 C 2018 6 5 16 1 1 列出了简单赋值的约束

随机推荐

  • Unity3D 性能优化

    优化思路 个人优化原则 三原则 注意细节 注意细节 注意细节 优化手段 1 善于使用工具 2 减少总量 3 空间 时间互换 4 由浅入深 1 善于使用工具 一定要善于使用工具来分析性能问题 Profiler 先找出性能瓶颈再做优化 2 减少
  • 菜鸟教程《Python 3 教程》笔记(19):错误与异常

    菜鸟教程 Python 3 教程 笔记 19 19 错误和异常 19 1 assert 断言 19 2 异常处理 19 2 1 try except 19 2 2 try except else 19 2 3 try finally 语句
  • JAVA获取类的类对象的三种方式

    自定义一个类 MyClass 并声明该类的对象 class MyClass MyClass mClass1 new MyClass 1 2 3 在上面说过 Class 类的构造方法是私有的 只有 java 虚拟机可以调用该方法创建该类的对象
  • Linux下Qt 5.15.2源码下载及编译

    一 下载 Qt的官方下载地址 Qt Downloads Qt 5 15 2源码下载路径 archive qt 5 15 5 15 2 single qt everywhere src 5 15 2 zip 二 编译源码 Qt官网提供了编译前
  • Verilog的基础知识

    Verilog的基本介绍 硬件描述语言发展至今已有二十多年历史 当今业界的标准中 IEEE标准 主要有VHDL和Verilog HDL 这两种硬件描述语言 一个设计往往从系统级设计开始 把系统划分成几个大的基本的功能模块 每个功能模块再按一
  • centos6.5linux安装docker之升级内核

    1 没有ssl 安装之 yum y install curl nss openssl 2 升级内核 参考博文https blog csdn net lvshuocool article details 79540617 1 gt 导入pub
  • DTD && Schema

    XML约束简介 XML文档都是自定义标签 所以编写起来比较随意自由 所以我们要给XML文档创建一个规则 我们需要在遵守相应的规则的前提下来编写XML文档 XML约束共有两种形式 DTD Schema DTD 文档类型定义 DTD可以定义文档
  • 【万字总结篇】C++STL常用算法详解(错等年系列)

    写在前面 本小菜鸟是一名热爱编程的大二在校生 目前主要精力放在学习C 数据结构和算法上 目前C 这个专栏的博客我已经总结完了C 常用的容器 内置函数对象 仿函数 还有此篇常用的内置算法 都是一些C STL的内容 因为这部分内容不难 并且需要
  • git fetch & git pull 总结

    一 git fetch git pull 图解 最开始 github 上存放着我们的远程仓库代码 然后在本地通过 git clone 命令 将远程仓库拉取到本地仓库 此时 本地仓库的 origin master 的内容 是远程仓库 mast
  • AS配置NDK开发环境,附CMake、NDK-build构建工具用法

    注意 Android Studio需要是1 3及以上版本 且版本号小于2 2 见文末说明 步骤1 新建一个项目 打开Project Structure 设置Android NDK Location目录 如果没有提前下载NDK包 可打开SDK
  • 分享两种实现图片验证码校验登录方法

    第一种使用ValidateCode实现验证码 ValidateCode是第三方依赖包 我们要先通过命令行引用一下 1 添加jar包到本地仓库 mvn install install file DgroupId cn dsna util im
  • 使用python暴力破解ZIP、7Z 、RAR格式压缩包密码教程

    使用python暴力破解ZIP 7Z RAR格式压缩包密码教程 目录 使用python暴力破解ZIP 7Z RAR格式压缩包密码教程 一 摘要 二 使用zipfile包暴力破解ZIP 7Z格式压缩包密码 三 使用unrar包暴力破解RAR格
  • 面试官问:如何快速开发一个类似微信的聊天系统?

    去年我们公司要我去面试一位候选人 当时刚好我接手了公司的 IM 系统 借这个机会 就问了候选人这个问题 如何快速开发一个类似微信的聊天系统 这个问题的确让候选人回答起来很吃力 从分析 PC 端微信界面的实现到怎么处理框体也业务代码分离 从通
  • hibernate学习之hibernate的入门

    hibernate 可能对于我并不是很陌生 一个基于面向对象来操作SQL语句的框架 也就是一种ORM框架 在Java对象与关系型数据库之间建立某种映射 来实现直接存取Java对象 特点 将对数据库的操作直接转换为Java对象的操作 简化开发
  • flvplayer.swf flv视频播放器使用方法

    今天由于网页上要加入一个视频文件 就研究了一下flv视频播放器flvplayer swf 一 直接在html文件中加载 复制代码代码如下 div div
  • mybatis 加载顺序

    1 加载配置文件 解析配置文件 MyBatis基于XML配置文件创建Configuration对象的过程 2 SqlSessionFactoryBuilder根据传入的数据流生成Configuration对象 然后根据Configurati
  • 最常见的Java框架有哪些?

    Java语言仍然是程最受欢迎的编程语言之一 如果你想进入这个行业 Java可以引导你 很多初学者可能没有系统的了解过Java框架 今日为大家整理一下常见的Java框架有哪些 Java框架 一 Spring框架 Spring框架是Java后端
  • 区块链数字签名、验签,以及椭圆曲线算法JS库—elliptic的使用

    目录 一 简介 二 椭圆曲线密码elliptic 1 安装elliptic和js sha3 2 Keccak256 3 签名过程 一 简介 数字签名是一种将类似现实世界中物理签名 盖章
  • 更改element button 按钮颜色

    在全局的index scss里面改 显示时按钮样式 el button inblack 需要更改的按钮类型 background 060606 important border color 060606 important color ff
  • AppDomain一——基本原理

    一 问题的提出 技术一定是为了解决某个应用场景的问题而产生的 很多时候 我们都想使用 开发 USB式 热插拔 的应用 例如 开发一个WinForm应用 并且这个WinForm应用能允许开发人员定制扩展插件 我们不能关闭程序 在把新的dll替