DownOL 软件仓库– 软件下载,字节世界与新知

了解进程,应用程序域和程序集

发表于:2024-04-26 作者:创始人
编辑最后更新 2024年04月26日,处理进程是操作系统的概念,是Windows操作系统提供的最小隔离单元。在Windows中运行的每个应用程序或代码片段都在进程的边界下运行。应用程序隔离确保一个进程的失败不会影响另一个进程的功能。还有必

处理

进程是操作系统的概念,是Windows操作系统提供的最小隔离单元。在Windows中运行的每个应用程序或代码片段都在进程的边界下运行。应用程序隔离确保一个进程的失败不会影响另一个进程的功能。还有必要确保在一个应用程序中运行的代码不会对其他应用程序产生不利影响。

当您运行应用程序时,Windows使用特定的进程ID和其他属性为应用程序创建一个进程。每个进程都分配了必要的内存和一组资源。

每个Windows进程至少包含一个负责应用程序执行的线程。一个进程可以有很多线程,它们加快了执行速度,提高了响应速度,但是包含一个主执行线程的进程被认为是更加线程安全的。

在图1中,您可以看到如何列出机器中运行的进程。每个进程都有名称,标识,描述等,每个进程可以使用进程ID唯一标识。

System.Diagnostics提供了许多类来处理流程,包括Process类。

图1

让我们尝试一个使用C#的应用程序来演示使用过程。清单1中的代码解释了两个问题:

如何启动进程,如何终止进程。

  1. using System;

  2. using System.Diagnostics;

  3. namespace SampleProcess

  4. {

  5. publicclass SomeProcess

  6. {

  7. publicstaticvoid Main(string[] args)

  8. {

  9. Process myProcess = new Process();

  10. try

  11. {

  12. // myProcess.StartInfo.UseShellExecute = false;

  13. // You can start any process, HelloWorld is a do-nothing example.

  14. myProcess.StartInfo.FileName = @"C:\Users\[UserID]\source\repos\BMIRuleEngine\BMIRuleEngine.exe";

  15. // myProcess.StartInfo.CreateNoWindow = true;

  16. myProcess.Start();

  17. // The process you are starting should terminate itself.

  18. // If you set CreateNoWindow = true, the application will run without a window and

  19. // it must terminate itself or you can do it programmatically from this application using the Kill method.

  20. // Do your other tasks here

  21. // Let us kill the process which we created, because my application doesn't terminate by itself.

  22. Process[] processes = Process.GetProcessesByName("BMIRuleEngine");

  23. foreach(Process process in processes)

  24. {

  25. process.Kill();

  26. }

  27. }

  28. catch (Exception ex)

  29. {

  30. Console.WriteLine(ex.Message);

  31. }

  32. }

  33. }

  34. }

清单1

  • StartInfo - 获取或设置要传递给Process的Process.Start()的属性。

  • StartInfo.CreateNoWindow - 帮助您指定是否需要使用窗口或不使用窗口来运行应用程序。

  • StartInfo.UseShellExecute - 帮助您指定是否使用操作系统shell来启动进程。如果将UseShellExecute设置为True,则应用程序将使用操作系统shell来启动进程。在OS shell中,您可以启动任何文档(这是与具有默认打开操作的可执行文件相关联的任何已注册文件类型),并使用Process对象对文件(如打印)执行操作。如果将UseShellExecute设置为false,则只能使用Process对象启动可执行文件。

  • 参数 - 帮助您指定传递给应用程序的参数。

Process class还有很多其他有用的属性,请检查一下。

应用程序域

Application Domain或AppDomain是.NET框架最强大的功能之一。AppDomain可以被认为是一个轻量级的过程。应用程序域是一个.NET概念,而过程是一个操作系统的概念。两者有许多共同的特点。一个进程可以包含多个应用程序域,并且每个应用程序域在该进程中提供一个隔离单元

应用程序域提供了在不同应用程序域中运行代码之间的隔 应用程序域就像进程一样是代码和数据的逻辑容器,具有独立的内存空间和对资源的访问。应用程序域也可以像服务器一样处理边界,以避免意外或非法尝试访问另一个正在运行的应用程序中的对象的数据。

System.AppDomain类为您提供了处理应用程序域的方法。它提供了创建新的应用程序域,从内存中卸载域等方法。

为什么我们需要应用程序域,而我们有过程

这是我第一次听到应用程序域时想到的第一个问题。

一个过程是更重和昂贵的创建和维护。所以,服务器在管理流程方面会很困难。所以,当微软开发.Net框架时,他们引入了应用程序域的概念,它是.net框架的一个组成部分。

尽管AppDomain仍然提供了Windows进程提供的许多功能,但是它们比一个进程更高效,因为多个程序集可以在独立的应用程序域中运行,而无需启动单独的进程。与创建过程相比,应用程序域相对便宜,维护的开销相对较少。

想想一台容纳数百个应用程序的服务器。在引入应用程序域之前,每个运行的应用程序都用于创建一个进程。AppDomain对于承载数百个应用程序的ISP(Internet服务提供商)具有很大的优势。因为每个应用程序都可以包含在一个应用程序域中,并且一个进程可以包含这样的AppDomain,因此提供了大量的成本节约。

简而言之,运行托管应用程序的任何进程都将至少有一个应用程序域。由于AppDomain是.NET的概念,任何运行非托管代码的进程都不会有任何应用程序域。

图2将帮助您更好地理解这个概念。

图2

进程A运行带有一个应用程序域的托管代码,而进程B运行托管代码有三个应用程序域。请注意,运行非托管代码的进程C没有应用程序域。

代码和数据使用AppDomain提供的边界安全隔离。如果两个AppDomain想要相互通信对象,则应使用.NET技术(如Remoting或Web服务)。

应用程序域示例

创建控制台应用程序

我正在使用Visual Studio 2017进行演示。

文件 - >新建 - >项目

在左侧窗格中,Visual C# - > Windows经典桌面

在右侧窗格中,选择控制台应用程序。

或者,您可以在位于窗口右上角的搜索框中键入控制台应用程序,然后选择要创建的解决方案的类型。

将有控制台应用程序(.NET Framework)和控制台应用程序(.NET Core)。

如果您打算仅在Windows中使用该应用程序,请选择.NET框架之一。

.NET Core项目将帮助您创建可在Windows,Linux和MacOS上的.NET Core上运行的命令行应用程序。

就我们的目的而言,.NET框架就足够了。

上述两种类型的应用程序都有一个Visual C#版本和一个Visual Basic版本,根据您要使用哪种语言选择正确的版本。

我将使用C#而不是VB。

将该项目命名为AppDomainSample,然后单击确定。

图3

将清单2中所示的下面的代码添加到Program类并构建应用程序。

我会告诉你如何创建一个应用程序域。

  1. using System;

  2. namespace AppDomainSample

  3. {

  4. class Program

  5. {

  6. staticvoid Main(string[] args)

  7. {

  8. // Get the current application domain

  9. AppDomain appDomain1 = AppDomain.CurrentDomain;

  10. Console.WriteLine("App Domain Name : '{0}'", AppDomain.CurrentDomain.FriendlyName);

  11. Console.WriteLine("ID of the Domain : '{0}'", AppDomain.CurrentDomain.Id);

  12. Console.ReadKey();

  13. }

  14. }

  15. }

清单2

你可以在图4中看到; 应用程序域是默认创建的,代码在该应用程序域下运行。

图4

要创建一个新的应用程序域,只需添加下面的代码行。

  1. AppDomain newAppDomain = AppDomain.CreateDomain("NewAppDomain" );

它将创建一个名称为NewAppDomain的应用程序域。

大会

按照微软的说法,"程序集是形成功能逻辑单元的类型和资源的集合。.NET Framework中的所有类型都必须存在于程序集中; 公共语言运行时不支持程序集以外的类型。程序集是要求和授予安全许可权的单元。"

更简单的说,当你在.NET中创建控制台应用程序,或者Windows窗体应用程序或类库或其他类型的应用程序时,你正在创建一个程序集。程序集可以是.exe或.dll。控制台应用程序在类库创建.dll时创建和.exe。

当您在应用程序中添加对另一个项目或.dll的引用时,您正在将程序集载入到您的项目中。这是一个静态的程序集绑定方式,因为您知道在编译之前要装入哪个程序集。所以,你很容易在这些程序集中创建类的对象并使用它们的方法。

在有些情况下,你将不得不在动态载入程序集的时间。System.Reflection.Assembly类提供了载入程序集的不同方法 - Assembly.Load(),Assembly.LoadFrom(),Assembly.LoadFile()。

使用这些方法将程序集载入到当前的应用程序域中。

装配载入示例

我要创建另一个控制台应用程序。

这一次,我正在离开默认名称。

这将创建一个名为ConsoleApp1的新控制台应用程序。

图5

只需在Main方法中添加一行代码,并添加GetAssemblyName()作为公共方法。

  1. using System;

  2. namespace ConsoleApp1

  3. {

  4. publicclass Program

  5. {

  6. staticvoid Main(string[] args)

  7. {

  8. Console.WriteLine("Assembly Loading Demo.");

  9. }

  10. public string GetAssemblyName()

  11. {

  12. Console.WriteLine("This is ConsoleApp1!");

  13. Console.WriteLine("App Domain Name : '{0}'", AppDomain.CurrentDomain.FriendlyName);

  14. Console.WriteLine("ID of the Domain : '{0}'", AppDomain.CurrentDomain.Id);

  15. return AppDomain.CurrentDomain.FriendlyName;

  16. }

  17. }

  18. }

清单3

在动态载入的程序集中创建一个类/类型的对象,并用Reflection动态地调用一个方法

现在回到AppDomainSample项目,并将下面的代码添加到Main方法。

  1. //使用路径将程序集载入到当前的应用程序域中。

  2. Assembly a = Assembly.LoadFrom(@ "C:\ Users \ u23027 \ source \ repos \ ConsoleApp1 \ ConsoleApp1 \ bin \ Debug \ ConsoleApp1.exe" );

  3. //获取ConsoleApp1的Program类以在此处使用。

  4. 类型programClass = a.GetType("ConsoleApp1.Program" );

  5. //获取方法GetAssemblyName方法进行调用。

  6. MethodInfo getAssemblyName = programClass.GetMethod("GetAssemblyName" );

  7. //创建一个实例o。

  8. object programObject = Activator.CreateInstance(programClass);

  9. //执行GetAssemblyName方法。

  10. getAssemblyName.Invoke(programObject, null );

  11. Console.ReadKey();

清单4

您需要添加对System.Reflection名称空间的引用。

程序集ConsoleApp1.exe将被载入到与AppDomainSample运行相同的应用程序域。

您可以通过查看程序的输出来验证这一点,如图6所示。

即使在静态载入程序集时,程序集也会载入到当前的AppDomain上,我的意思是在编译之前添加对项目的引用。

图6

用Reflection动态调用静态方法

为了调用一个静态方法,你只需要对调用一个实例方法的代码做一些改变。

您不需要创建类的实例。

在这个例子中,你可以评论这一行:

  1. object programObject = Activator.CreateInstance(programClass);

在调用方法时,不需要将对象作为参数传递,因此将其作为null传递。

所以,代码将会改变如下:

  1. getAssemblyName.Invoke(null , null );

内存和性能

正如我们所看到的,程序集被载入到当前的应用程序域中。这可能会在有大型程序集载入或程序集数量增加时产生内存问题。

因此,一旦执行它,最好卸载不需要的程序集。

您可以使用AppDomain类的Unload方法卸载应用程序域的内容(所有程序集)。

  1. AppDomain.Unload(appDomainObject);

但是,一旦程序集载入了应用程序域,就无法从AppDomain单独卸载程序集。

为了克服这一点,我们可以创建一个新的应用程序域,并在那里载入新的程序集。然后,在执行新程序集之后,可以安全地卸载新的应用程序域。

这种方法有两个好处,

  1. 所有不需要的程序集都从内存中删除。

  2. 主应用程序线程和相关引用在内存中维护。

将程序集载入到应用程序域中,并使用AppDomain类执行它

创建一个新的应用程序域。

  1. AppDomain newAppDomain = AppDomain.CreateDomain("NewAppDomain" );

NewAppDomain是AppDomain的名称。

  1. newAppDomain.ExecuteAssembly(@ "C:\ Users \ u23027 \ source \ repos \ ConsoleApp1 \ ConsoleApp1 \ bin \ Debug \ ConsoleApp1.exe" );

上面的代码行将会将程序集ConsoleApp1载入到NewAppDomain应用程序域中,并开始执行它。

完成新程序集的执行后,可以使用以下命令卸载它:

  1. AppDomain.Unload(newAppDomain);

要测试ConsoleApp1是否载入到新的应用程序域中,请转到ConsoleApp1项目并将以下两行添加到Main方法。

  1. Console.WriteLine("App Domain Name:'{0}'" ,AppDomain.CurrentDomain.FriendlyName);

  2. Console.WriteLine("域的ID:"{0}" ,AppDomain.CurrentDomain.Id);

现在构建ConsoleApp1项目并构建并运行AppDomainSample项目。

图7

您可以看到ConsoleApp1项目已载入到我们创建的NewAppDomain应用程序域中。

源代码附在本文中。

您可以尝试使用Assembly,AppDomain和Process类的其他方法。

参考

  • https://msdn.microsoft.com/en-us/library/system.diagnostics.process(v=vs.110).aspx

  • https://docs.microsoft.com/en-us/dotnet/framework/app-domains/application-domains

  • https://docs.microsoft.com/en-us/dotnet/framework/deployment/best-practices-for-assembly-loading

  • https://msdn.microsoft.com/en-us/library/43wc4hhs(v=vs.100).aspx

  • https://docs.microsoft.com/en-us/dotnet/framework/app-domains/how-to-load-assemblies-into-an-application-domain

  • http://www.c-sharpcorner.com/UploadFile/84c85b/clr-internals-process-and-application-domain/

  • http://www.dotnetspider.com/forum/ViewForum.aspx?ForumId=139934

  • https://www.codeproject.com/Articles/597398/Loading-Assemblies-using-Assemb

    2022-05-09 12:51:11
    0