應用程式定義域Application domains

作業系統和執行階段環境通常會在應用程式之間提供某種形式的隔離。Operating systems and runtime environments typically provide some form of isolation between applications. 例如,Windows 會使用處理序來隔離應用程式。For example, Windows uses processes to isolate applications. 這種隔離確保在某一應用程式中執行之程式碼不會對其他不相關應用程式造成負面影響。This isolation is necessary to ensure that code running in one application cannot adversely affect other, unrelated applications.

應用程式定義域針對組件的安全性、可靠性和版本控制以及卸載提供了隔離界限。Application domains provide an isolation boundary for security, reliability, and versioning, and for unloading assemblies. 應用程式定義域通常是由負責在應用程式執行前啟動 Common Language Runtime 的執行階段主應用程式所建立。Application domains are typically created by runtime hosts, which are responsible for bootstrapping the common language runtime before an application is run.

隔離應用程式的優點The benefits of isolating applications

在過去,一直是用處理序 (Process) 界限來隔離在同一電腦上執行的應用程式。Historically, process boundaries have been used to isolate applications running on the same computer. 每個應用程式都會被載入用來分隔在同一電腦上執行之不同應用程式的個別處理序中。Each application is loaded into a separate process, which isolates the application from other applications running on the same computer.

這些應用程式所以能被分隔,是因為記憶體位址是相對於處理序;從一個處理序傳遞到另一個處理序的記憶體指標,在目標處理序中無法以任何有意義的方式使用。The applications are isolated because memory addresses are process-relative; a memory pointer passed from one process to another cannot be used in any meaningful way in the target process. 此外,您也不能在兩個處理序之間直接進行呼叫。In addition, you cannot make direct calls between two processes. 而必須使用提供了一層間接取值 (Indirection) 的 Proxy。Instead, you must use proxies, which provide a level of indirection.

Managed 程式碼必須通過驗證程序才能夠執行 (除非系統管理員已授予略過驗證的使用權限)。Managed code must be passed through a verification process before it can be run (unless the administrator has granted permission to skip the verification). 驗證過程中會決定程式碼是否可能嘗試存取無效的記憶體位址,或執行可能導致執行該程式碼之處理序無法正常運作的動作。The verification process determines whether the code can attempt to access invalid memory addresses or perform some other action that could cause the process in which it is running to fail to operate properly. 通過驗證測試的程式碼被稱為型別安全。Code that passes the verification test is said to be type-safe. 驗證程式碼是否為型別安全的能力,可以讓 Common Language Runtime 以極低的效能損失,提供盡可能與處理序界限同樣高的隔離等級。The ability to verify code as type-safe enables the common language runtime to provide as great a level of isolation as the process boundary, at a much lower performance cost.

應用程式定義域提供了安全且多用途的處理單位,可以讓 Common Language Runtime 用來提供應用程式間的隔離。Application domains provide a more secure and versatile unit of processing that the common language runtime can use to provide isolation between applications. 使用存在於個別處理序中的相同隔離等級,您可以在單一處理序中執行好幾個應用程式定義域,而不會造成進行跨處理序呼叫或在處理序間切換的額外負荷。You can run several application domains in a single process with the same level of isolation that would exist in separate processes, but without incurring the additional overhead of making cross-process calls or switching between processes. 在單一處理序中執行多個應用程式的能力大幅增加了伺服器的延展性 (Scalability)。The ability to run multiple applications within a single process dramatically increases server scalability.

隔離應用程式對於應用程式安全性也極為重要。Isolating applications is also important for application security. 例如,您可以從單一瀏覽器處理序中的幾個 Web 應用程式執行一些控制項,而且以此方法讓這些控制項不能存取彼此的資料和資源。For example, you can run controls from several Web applications in a single browser process in such a way that the controls cannot access each other's data and resources.

應用程式定義域提供的隔離具有以下優點:The isolation provided by application domains has the following benefits:

  • 在某一應用程式中的錯誤不會影響其他應用程式。Faults in one application cannot affect other applications. 由於型別安全程式碼不會導致記憶體錯誤,所以使用應用程式定義域可確保在某一定義域中執行的程式碼不會影響處理序中的其他應用程式。Because type-safe code cannot cause memory faults, using application domains ensures that code running in one domain cannot affect other applications in the process.

  • 可以停止個別應用程式而不需停止整個處理序。Individual applications can be stopped without stopping the entire process. 使用應用程式定義域可以讓您卸載在單一應用程式中執行的程式碼。Using application domains enables you to unload the code running in a single application.

    注意

    您不能卸載個別組件或型別。You cannot unload individual assemblies or types. 只有完整的定義域可以卸載。Only a complete domain can be unloaded.

  • 在某一應用程式中執行的程式碼不能直接從其他應用程式存取程式碼或資源。Code running in one application cannot directly access code or resources from another application. Common Language Runtime 是藉由防止不同應用程式定義域中物件之間的呼叫來強制執行這種隔離。The common language runtime enforces this isolation by preventing direct calls between objects in different application domains. 在不同定義域之間傳遞的物件必須用複製方式傳遞或由 Proxy 存取。Objects that pass between domains are either copied or accessed by proxy. 如果物件是複製的,那麼對該物件的呼叫就是區域呼叫。If the object is copied, the call to the object is local. 也就是說,呼叫端和被參考的物件是在同一個應用程式定義域中。That is, both the caller and the object being referenced are in the same application domain. 如果物件是透過 Proxy 存取,那麼對物件的呼叫便是遠端呼叫。If the object is accessed through a proxy, the call to the object is remote. 在這種情況下,呼叫端和被參考的物件是在不同的應用程式定義域中。In this case, the caller and the object being referenced are in different application domains. 跨定義域呼叫是使用與兩個處理序或兩部電腦之間呼叫相同的遠端呼叫基礎結構。Cross-domain calls use the same remote call infrastructure as calls between two processes or between two machines. 因此,所參考之物件的中繼資料 (Metadata) 必須在這兩個應用程式定義域中都能使用,才能讓該方法呼叫被 JIT 適當地編譯。As such, the metadata for the object being referenced must be available to both application domains to allow the method call to be JIT-compiled properly. 如果呼叫定義域無權存取所呼叫物件的中繼資料,則編譯可能會失敗,並擲回 FileNotFoundException 類型的例外狀況。If the calling domain does not have access to the metadata for the object being called, the compilation might fail with an exception of type FileNotFoundException. 如需詳細資訊,請參閱 Remote ObjectsFor more information, see Remote Objects. 決定如何跨定義域存取物件的機制是由該物件決定。The mechanism for determining how objects can be accessed across domains is determined by the object. 如需詳細資訊,請參閱System.MarshalByRefObjectFor more information, see System.MarshalByRefObject.

  • 程式碼的行為範圍是由執行該程式碼的應用程式決定。The behavior of code is scoped by the application in which it runs. 換言之,應用程式定義域會提供應用程式版本原則、它所取之任何遠端組件的位置,以及有關在哪裡尋找載入定義域中之組件等組態設定。In other words, the application domain provides configuration settings such as application version policies, the location of any remote assemblies it accesses, and information about where to locate assemblies that are loaded into the domain.

  • 授予程式碼的使用權限可以由執行該程式碼的應用程式定義域控制。Permissions granted to code can be controlled by the application domain in which the code is running.

應用程式定義域和組件Application domains and assemblies

本節描述應用程式定義域和組件之間的關聯性。This section describes the relationship between application domains and assemblies. 您必須先將組件載入到應用程式定義域之後,才能執行它所包含的程式碼。You must load an assembly into an application domain before you can execute the code it contains. 執行一個典型的應用程式會讓好幾個組件載入應用程式定義域。Running a typical application causes several assemblies to be loaded into an application domain.

載入組件的方式會決定其 Just-in-Time (JIT) 編譯程式碼是否能在處理序中由多個應用程式定義域所共用,以及組件是否能夠從處理序卸載。The way an assembly is loaded determines whether its just-in-time (JIT) compiled code can be shared by multiple application domains in the process, and whether the assembly can be unloaded from the process.

  • 如果組件是以定義域中性方式 (Domain-neutral) 載入,所有共用相同安全性授權集的應用程式定義域,也就都能共用相同的 JIT 編譯程式碼,進而減少應用程式所需要的記憶體。If an assembly is loaded domain-neutral, all application domains that share the same security grant set can share the same JIT-compiled code, which reduces the memory required by the application. 然而,組件則會永遠無法從處理序中卸載。However, the assembly can never be unloaded from the process.

  • 如果組件不是以定義域中性方式載入,則在載入該組件的每一個應用程式定義域中,都必須是 JIT 編譯的。If an assembly is not loaded domain-neutral, it must be JIT-compiled in every application domain in which it is loaded. 然而,只要卸載所有載入該組件的應用程式定義域,即可從處理序中卸載組件。However, the assembly can be unloaded from the process by unloading all the application domains in which it is loaded.

執行階段主機會判斷將執行階段載入處理序時,是否要以定義域中性方式載入組件。The runtime host determines whether to load assemblies as domain-neutral when it loads the runtime into a process. 針對 Managed 應用程式,會將 LoaderOptimizationAttribute 屬性 (Attribute) 套用到處理序的進入點方法,並從關聯的 LoaderOptimization 列舉型別 (Enumeration) 中指定值。For managed applications, apply the LoaderOptimizationAttribute attribute to the entry-point method for the process, and specify a value from the associated LoaderOptimization enumeration. 針對裝載 Common Language Runtime 的 Unmanaged 應用程式,指定您在呼叫 CorBindToRuntimeEx 函式方法時的適當旗標。For unmanaged applications that host the common language runtime, specify the appropriate flag when you call the CorBindToRuntimeEx Function method.

載入定義域中性組件的選項有三種:There are three options for loading domain-neutral assemblies:

  • 除了永遠以定義域中性方式載入的 Mscorlib 之外,LoaderOptimization.SingleDomain 不會以定義域中性方式載入任何組件。LoaderOptimization.SingleDomain loads no assemblies as domain-neutral, except Mscorlib, which is always loaded domain-neutral. 這種設定稱為單一定義域,因為它通常使用於裝載程式只在處理序中執行單一應用程式的情況。This setting is called single domain because it is commonly used when the host is running only a single application in the process.

  • LoaderOptimization.MultiDomain 會將所有組件都以定義域中性方式載入。LoaderOptimization.MultiDomain loads all assemblies as domain-neutral. 處理序中有多個應用程式定義域,而且它們全部都執行相同的程式碼時,請使用這種設定。Use this setting when there are multiple application domains in the process, all of which run the same code.

  • 如果強式名稱組件及其所有相依性項目都已安裝在全域組件快取中,LoaderOptimization.MultiDomainHost 便會以定義域中性方式載入這些組件。LoaderOptimization.MultiDomainHost loads strong-named assemblies as domain-neutral, if they and all their dependencies have been installed in the global assembly cache. 其他組件都會分別載入並針對載入組件的每個應用程式定義域進行 JIT 編譯,因此這些組件都可以從處理序中卸載。Other assemblies are loaded and JIT-compiled separately for each application domain in which they are loaded, and thus can be unloaded from the process. 在相同處理序中執行多個應用程式時,或是有許多應用程式定義域及組件 (需要從處理序卸載) 共用的混合組件時,請使用這項設定。Use this setting when running more than one application in the same process, or if you have a mixture of assemblies that are shared by many application domains and assemblies that need to be unloaded from the process.

對於使用 LoadFrom 類別 (Class) 的 Assembly 方法將載入內容載入的組件,以及使用指定位元組陣列之 Load 方法的多載而自影像載入組件,都無法共用 JIT 編譯程式碼。JIT-compiled code cannot be shared for assemblies loaded into the load-from context, using the LoadFrom method of the Assembly class, or loaded from images using overloads of the Load method that specify byte arrays.

已經使用 Ngen.exe (原生映像產生器) 編譯成機器碼的組件,如果在第一次載入處理序時,是以定義域中性方式載入的,就可以在應用程式定義域之間共用。Assemblies that have been compiled to native code by using the Ngen.exe (Native Image Generator) can be shared between application domains, if they are loaded domain-neutral the first time they are loaded into a process.

針對包含應用程式進入點的組件,只有在能夠共用組件的所有相依性項目時,才能共用其 JIT 編譯程式碼。JIT-compiled code for the assembly that contains the application entry point is shared only if all its dependencies can be shared.

對於以定義域中性方式載入的組件,可以進行一次以上的 JIT 編譯。A domain-neutral assembly can be JIT-compiled more than once. 例如,當兩個應用程式定義域的安全性授權集不同時,兩者就不能共用相同的 JIT 編譯程式碼。For example, when the security grant sets of two application domains are different, they cannot share the same JIT-compiled code. 然而,JIT 編譯組件的每個複本都能與具有相同授權集的其他應用程式定義域共用。However, each copy of the JIT-compiled assembly can be shared with other application domains that have the same grant set.

在決定是否要將組件以定義域中性方式載入時,您必須在減少記憶體使用與其他效能考量之間做出取捨。When you decide whether to load assemblies as domain-neutral, you must make a tradeoff between reducing memory use and other performance factors.

  • 對於定義域中性的組件,存取靜態資料和方法會比較緩慢,這是因為需要隔離組件。Access to static data and methods is slower for domain-neutral assemblies because of the need to isolate assemblies. 存取該組件的每一個應用程式定義域都必須有靜態資料的單獨複本,以避免靜態欄位中物件的參考跨越定義域界限。Each application domain that accesses the assembly must have a separate copy of the static data, to prevent references to objects in static fields from crossing domain boundaries. 而其結果是,執行階段會含有額外的邏輯以便將呼叫端導向至靜態資料或方法的適當複本。As a result, the runtime contains additional logic to direct a caller to the appropriate copy of the static data or method. 這些額外的邏輯就會讓呼叫慢下來。This extra logic slows down the call.

  • 在將組件以定義域中性方式載入時,必須找到和載入組件的所有相依性項目。這是因為無法以定義域中性方式載入的相依性項目,也會使組件無法以定義域中性方式載入。All the dependencies of an assembly must be located and loaded when the assembly is loaded domain-neutral, because a dependency that cannot be loaded domain-neutral prevents the assembly from being loaded domain-neutral.

應用程式定義域和執行緒Application domains and threads

應用程式定義域會形成 Managed 程式碼的安全性、版本控制、可靠性及卸載的隔離界限。An application domain forms an isolation boundary for security, versioning, reliability, and unloading of managed code. 執行緒是 Common Language Runtime 用來執行程式碼的作業系統建構。A thread is the operating system construct used by the common language runtime to execute code. 在執行階段,所有 Managed 程式碼都會載入至應用程式定義域,並由一個或多個 Managed 執行緒來執行。At run time, all managed code is loaded into an application domain and is run by one or more managed threads.

在應用程式定義域和執行緒之間不是一對一的相互關聯。There is not a one-to-one correlation between application domains and threads. 數個執行緒可以在任何指定時間於單一應用程式定義域內執行,而一個特定的執行緒並不受限於單一的應用程式定義域。Several threads can execute in a single application domain at any given time, and a particular thread is not confined to a single application domain. 也就是說,執行緒可以自由跨越應用程式定義域界限;不會對每一應用程式定義域建立一個新的執行緒。That is, threads are free to cross application domain boundaries; a new thread is not created for each application domain.

在任何指定的時間,每個執行緒都會在一個應用程式定義域中執行。At any given time, every thread executes in an application domain. 可能會有零個、一個或多個執行緒在任何指定的應用程式定義域中執行。Zero, one, or multiple threads might be executing in any given application domain. 執行階段會不斷追蹤哪一個執行緒在哪一個應用程式定義域中執行。The runtime keeps track of which threads are running in which application domains. 您可以隨時呼叫 Thread.GetDomain 方法來找出有某個執行緒正在其中執行的定義域。You can locate the domain in which a thread is executing at any time by calling the Thread.GetDomain method.

應用程式定義域和文化特性Application domains and cultures

文化特性 (由 CultureInfo 物件表示) 會與執行緒產生關聯。Culture, which is represented by a CultureInfo object, is associated with threads. 您可以使用 CultureInfo.CurrentCulture 屬性取得與目前執行中執行緒相關聯的文化特性,也可以使用 Thread.CurrentCulture 屬性來取得或設定與目前執行中執行緒相關聯的文化特性。You can get the culture that is associated with the currently executing thread by using the CultureInfo.CurrentCulture property, and you can get or set the culture that is associated with the currently executing thread by using the Thread.CurrentCulture property. 如果已經使用 Thread.CurrentCulture 屬性明確設定與執行緒相關聯的文化特性,當執行緒跨越應用程式定義域界限時,文化特性會繼續與該執行緒相關聯。If the culture that is associated with a thread has been explicitly set by using the Thread.CurrentCulture property, it continues to be associated with that thread when the thread crosses application domain boundaries. 否則,在任何指定時間與執行緒相關聯的文化特性會由執行緒執行所在之應用程式定義域中的 CultureInfo.DefaultThreadCurrentCulture 屬性值決定:Otherwise, the culture that is associated with the thread at any given time is determined by the value of the CultureInfo.DefaultThreadCurrentCulture property in the application domain in which the thread is executing:

  • 如果該屬性的值不是 null,則該屬性所傳回的文化特性會與執行緒相關聯 (也因此會由 Thread.CurrentCultureCultureInfo.CurrentCulture 屬性傳回)。If the value of the property is not null, the culture that is returned by the property is associated with the thread (and therefore returned by the Thread.CurrentCulture and CultureInfo.CurrentCulture properties).

  • 如果該屬性的值為 null,則目前系統的文化特性會與執行緒相關聯。If the value of the property is null, the current system culture is associated with the thread.

使用應用程式定義域設計程式Programming with application domains

應用程式定義域通常是由執行階段主應用程式以程式方式建立和運用。Application domains are usually created and manipulated programmatically by runtime hosts. 不過,有時候應用程式也會希望配合應用程式定義域來運作。However, sometimes an application program might also want to work with application domains. 例如,應用程式可將應用程式元件載入到定義域中,如此才能夠卸載此定義域 (及此元件),而不需要停止整個應用程式。For example, an application program could load an application component into a domain to be able to unload the domain (and the component) without having to stop the entire application.

AppDomain 是應用程式定義域的程式設計介面。The AppDomain is the programmatic interface to application domains. 這個類別包括了一些方法,可用來建立及卸載定義域、建立定義域中的型別執行個體,以及註冊各種告知 (例如,應用程式定義域的卸載)。This class includes methods to create and unload domains, to create instances of types in domains, and to register for various notifications such as application domain unloading. 下表列出常用的 AppDomain 方法。The following table lists commonly used AppDomain methods.

AppDomain 方法AppDomain Method 描述Description
CreateDomain 建立新的應用程式定義域。Creates a new application domain. 建議您要使用指定 AppDomainSetup 物件的這個方法多載。It is recommended that you use an overload of this method that specifies an AppDomainSetup object. 這是設定新定義域之屬性的慣用方法,例如,應用程式基底或應用程式的根目錄;定義域組態檔的位置;以及 Common Language Runtime 要用來將組件載入定義域的搜尋路徑等屬性。This is the preferred way to set the properties of a new domain, such as the application base, or root directory for the application; the location of the configuration file for the domain; and the search path that the common language runtime is to use to load assemblies into the domain.
ExecuteAssemblyExecuteAssemblyByNameExecuteAssembly and ExecuteAssemblyByName 執行應用程式定義域中的組件。Executes an assembly in the application domain. 這是執行個體方法,所以可用來在另一個您擁有參考的應用程式定義域中執行程式碼。This is an instance method, so it can be used to execute code in another application domain to which you have a reference.
CreateInstanceAndUnwrap 在應用程式定義域中建立指定之型別的執行個體,並傳回 Proxy。Creates an instance of a specified type in the application domain, and returns a proxy. 使用這個方法可避免將包含建立之型別的組件載入到呼叫組件中。Use this method to avoid loading the assembly containing the created type into the calling assembly.
Unload 執行定義域的非失誤性的關閉。Performs a graceful shutdown of the domain. 一直要到在定義域中執行的所有執行緒都已停止或者已經離開定義域,應用程式定義域才會被卸載。The application domain is not unloaded until all threads running in the domain have either stopped or are no longer in the domain.

注意

Common Language Runtime 並不支援全域方法的序列化 (Serialization),因此不能使用委派 (Delegate) 在其他應用程式定義域中執行全域方法。The common language runtime does not support serialization of global methods, so delegates cannot be used to execute global methods in other application domains.

Common Language Runtime 裝載介面規格中描述的 Unmanaged 介面也可提供應用程式定義域的存取。The unmanaged interfaces described in the common language runtime Hosting Interfaces Specification also provide access to application domains. Runtime 主應用程式可以從 Unmanaged 程式碼使用這些介面來建立並且取得處理序內應用程式定義域的存取。Runtime hosts can use interfaces from unmanaged code to create and gain access to the application domains within a process.

COMPLUS_LoaderOptimization 環境變數The COMPLUS_LoaderOptimization environment variable

環境變數,用於設定可執行應用程式的預設載入器最佳化原則。An environment variable that sets the default loader optimization policy of an executable application.

語法Syntax

COMPLUS_LoaderOptimization = 1  

備註Remarks

一般的應用程式會將數個組件載入至應用程式定義域中,以便執行其中包含的程式碼。A typical application loads several assemblies into an application domain before the code they contain can be executed.

載入組件的方式會決定其 Just-In-Time (JIT) 編譯程式碼是否能在處理序中由多個應用程式定義域所共用。The way the assembly is loaded determines whether its just-in-time (JIT) compiled code can be shared by multiple application domains in the process.

  • 如果組件是以定義域中性 (Domain-neutral) 方式載入,所有共用相同安全性授權集的應用程式定義域都能共用相同的 JIT 編譯程式碼。If an assembly is loaded domain-neutral, all application domains that share the same security grant set can share the same JIT-compiled code. 這會減少應用程式所需要的記憶體。This reduces the memory required by the application.

  • 如果組件不是以定義域中性方式載入,則在載入該組件的每一個應用程式定義域中,該組件都必須是 JIT 編譯的,並且載入器不可以跨越應用程式定義域來共用內部資源。If an assembly is not loaded domain-neutral, it must be JIT-compiled in every application domain in which it is loaded and the loader must not share internal resources across application domains.

當設定為 1 時,COMPLUS_LoaderOptimization 環境旗標會強制執行階段主應用程式以稱為 SingleDomain 的非定義域中性方式載入所有組件。When set to 1, the COMPLUS_LoaderOptimization environment flag forces the runtime host to load all assemblies in non-domain-neutral way known as SingleDomain. 除了永遠以定義域中性方式載入的 Mscorlib 之外,SingleDomain 不會以定義域中性方式載入任何組件。SingleDomain loads no assemblies as domain-neutral, except Mscorlib, which is always loaded domain-neutral. 這種設定稱為單一定義域,因為它通常使用於裝載程式只在處理序中執行單一應用程式的情況。This setting is called single domain because it is commonly used when the host is running only a single application in the process.

警告

COMPLUS_LoaderOptimization 環境旗標是設計用於診斷及測試情節。The COMPLUS_LoaderOptimization environment flag was designed to be used in diagnostic and test scenarios. 開啟旗標可能會造成速度大幅減慢,並增加記憶體使用量。Having the flag turned on can cause severe slow-down and increase in memory usage.

程式碼範例Code example

若要強制所有組件不載入為 IISADMIN 服務的定義域中性組件,可透過將 COMPLUS_LoaderOptimization=1 附加至 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\IISADMIN 機碼中環境的多字串值來完成。To force all assemblies not to be loaded as domain-neutral for the IISADMIN service can be achieved by appending COMPLUS_LoaderOptimization=1 to the Environment’s Multi-String Value in the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\IISADMIN key.

Key = HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\IISADMIN  
Name = Environment  
Type = REG_MULTI_SZ  
Value (to append) = COMPLUS_LoaderOptimization=1  

請參閱See also