Managed 執行程序Managed Execution Process

Managed 執行處理序包含下列步驟,將於本主題中稍後詳細討論:The managed execution process includes the following steps, which are discussed in detail later in this topic:

  1. 選擇編譯器Choosing a compiler.

    若要享有 Common Language Runtime 帶來的好處,您必須使用一個或多個以執行階段為目標的語言編譯器。To obtain the benefits provided by the common language runtime, you must use one or more language compilers that target the runtime.

  2. 編譯您的程式碼為 MSILCompiling your code to MSIL.

    編譯會將您的原始程式碼轉譯成 Microsoft 中間語言 (MSIL),並產生必要的中繼資料。Compiling translates your source code into Microsoft intermediate language (MSIL) and generates the required metadata.

  3. 將 MSIL 編譯成機器碼Compiling MSIL to native code.

    在執行期間,Just-In-Time (JIT) 編譯器會將 MSIL 轉譯成機器碼。At execution time, a just-in-time (JIT) compiler translates the MSIL into native code. 在這個編譯期間,程式碼必須通過驗證程序,這會檢查 MSIL 和中繼資料,以了解是否可判斷程式碼為類型安全的。During this compilation, code must pass a verification process that examines the MSIL and metadata to find out whether the code can be determined to be type safe.

  4. 執行程式碼Running code.

    Common Language Runtime 提供基礎結構,啟用執行以及可在執行期間使用的服務。The common language runtime provides the infrastructure that enables execution to take place and services that can be used during execution.

選擇編譯器Choosing a Compiler

若要享有 Common Language Runtime (CLR) 帶來的好處,就必須使用一個或多個以執行階段為目標的語言編譯器,例如 Visual Basic、C#、Visual C++、F#,或眾多協力廠商編譯器的其中一種,例如 Eiffel、Perl 或 COBOL 編譯器。To obtain the benefits provided by the common language runtime (CLR), you must use one or more language compilers that target the runtime, such as Visual Basic, C#, Visual C++, F#, or one of many third-party compilers such as an Eiffel, Perl, or COBOL compiler.

因為是多種程式語言的執行環境,執行階段會支援各種資料類型和語言功能。Because it is a multilanguage execution environment, the runtime supports a wide variety of data types and language features. 您使用的語言編譯器將決定有哪些執行階段功能可用,而您可使用那些功能來設計程式碼。The language compiler you use determines which runtime features are available, and you design your code using those features. 編譯器會建立程式碼必須使用的語法,而不是由執行階段建立。Your compiler, not the runtime, establishes the syntax your code must use. 如果您的元件必須完全可用於其他語言撰寫的元件,元件的匯出類型必須只公開包含在 Language Independence and Language-Independent Components (CLS) 中的語言功能。If your component must be completely usable by components written in other languages, your component's exported types must expose only language features that are included in the Language Independence and Language-Independent Components (CLS). 您可以使用 CLSCompliantAttribute 屬性來確保您的程式碼符合 CLS 標準。You can use the CLSCompliantAttribute attribute to ensure that your code is CLS-compliant. 如需詳細資訊,請參閱 Language Independence and Language-Independent ComponentsFor more information, see Language Independence and Language-Independent Components.

回到頁首Back to top

編譯為 MSILCompiling to MSIL

編譯為 Managed 程式碼時,編譯器會將您的原始程式碼轉譯成 Microsoft 中間語言 (MSIL),這是一種與 CPU 無關的指令集,可以有效率地轉換為機器碼。When compiling to managed code, the compiler translates your source code into Microsoft intermediate language (MSIL), which is a CPU-independent set of instructions that can be efficiently converted to native code. MSIL 包括可用來載入、儲存、初始化和呼叫物件上方法的指令,以及用於算術和邏輯運算、控制流程、直接記憶體存取、例外處理和其他作業的指令。MSIL includes instructions for loading, storing, initializing, and calling methods on objects, as well as instructions for arithmetic and logical operations, control flow, direct memory access, exception handling, and other operations. 在程式碼可以執行之前,必須將 MSIL 轉換為 CPU 特定程式碼,而此轉換通常是由 Just-In-Time (JIT) 編譯器進行。Before code can be run, MSIL must be converted to CPU-specific code, usually by a just-in-time (JIT) compiler. 由於 Common Language Runtime 會為其支援的每一個電腦架構提供一個或多個 JIT 編譯器,因此相同的 MSIL 集可以在任何受支援的架構上進行 JIT 編譯並執行。Because the common language runtime supplies one or more JIT compilers for each computer architecture it supports, the same set of MSIL can be JIT-compiled and run on any supported architecture.

當編譯器產生 MSIL 時,它也會產生中繼資料。When a compiler produces MSIL, it also produces metadata. 中繼資料描述您程式碼中的類型,包括各個類型的定義、各個類型成員的簽章、您的程式碼所參考的成員,和執行階段在執行期間使用的其他資料。Metadata describes the types in your code, including the definition of each type, the signatures of each type's members, the members that your code references, and other data that the runtime uses at execution time. MSIL 和中繼資料會包含在可攜式執行 (PE) 檔中,該檔案根據已發行的 Microsoft PE,以及過去供可執行檔內容使用的通用物件檔案格式 (COFF) 為基礎並對這些加以擴充。The MSIL and metadata are contained in a portable executable (PE) file that is based on and that extends the published Microsoft PE and common object file format (COFF) used historically for executable content. 這種檔案格式 (適用於 MSIL 或機器碼以及中繼資料) 使作業系統能夠辨認 Common Language Runtime 的映像。This file format, which accommodates MSIL or native code as well as metadata, enables the operating system to recognize common language runtime images. 檔案內存在的中繼資料連同 MSIL 讓您的程式碼能夠描述自己,也就是說,不需要類型程式庫或介面定義語言 (IDL)。The presence of metadata in the file together with MSIL enables your code to describe itself, which means that there is no need for type libraries or Interface Definition Language (IDL). 此執行階段視需要會在執行期間從檔案找出中繼資料並擷取。The runtime locates and extracts the metadata from the file as needed during execution.

回到頁首Back to top

將 MSIL 編譯成機器碼Compiling MSIL to Native Code

Microsoft 中間語言 (MSIL) 必須先根據 Common Language Runtime 編譯成機器碼才能執行 (該程式碼是根據目標電腦架構來編譯)。Before you can run Microsoft intermediate language (MSIL), it must be compiled against the common language runtime to native code for the target machine architecture. .NET Framework 提供兩種執行這項轉換的方式:The .NET Framework provides two ways to perform this conversion:

使用 JIT 編譯器編譯Compilation by the JIT Compiler

當載入和執行組件內容時,JIT 編譯會視需要於應用程式執行階段將 MSIL 轉換成機器碼。JIT compilation converts MSIL to native code on demand at application run time, when the contents of an assembly are loaded and executed. 由於 Common Language Runtime 會為每個支援的 CPU 架構提供 JIT 編譯器,因此開發人員可以建置可在不同架構的電腦上進行 JIT 編譯和執行的 MSIL 組件集。Because the common language runtime supplies a JIT compiler for each supported CPU architecture, developers can build a set of MSIL assemblies that can be JIT-compiled and run on different computers with different machine architectures. 然而,如果您的 Managed 程式碼呼叫特定平台的原生 API 或特定平台的類別庫,便只能在特定的作業系統上執行。However, if your managed code calls platform-specific native APIs or a platform-specific class library, it will run only on that operating system.

JIT 編譯還會考慮到在執行期間可能永遠不會呼叫某些程式碼。JIT compilation takes into account the possibility that some code might never be called during execution. 它並不耗用時間和記憶體將可攜式執行檔中所有的 MSIL 轉換為機器碼,而是在執行期間視需要轉換 MSIL 並在記憶體中儲存產生的機器碼,以供該處理序內容中的後續呼叫存取。Instead of using time and memory to convert all the MSIL in a PE file to native code, it converts the MSIL as needed during execution and stores the resulting native code in memory so that it is accessible for subsequent calls in the context of that process. 載入類型並初始化時,載入器會建立虛設常式並附加至類型中的每一個方法。The loader creates and attaches a stub to each method in a type when the type is loaded and initialized. 初次呼叫方法時,虛設常式會將控制項傳遞至 JIT 編譯器,該編譯器會將此方法的 MSIL 轉換成機器碼,並且修改虛設常式為直接指向產生的機器碼。When a method is called for the first time, the stub passes control to the JIT compiler, which converts the MSIL for that method into native code and modifies the stub to point directly to the generated native code. 因此,JIT 編譯方法的後續呼叫會直接移至機器碼。Therefore, subsequent calls to the JIT-compiled method go directly to the native code.

使用 NGen.exe 產生安裝期間程式碼Install-Time Code Generation Using NGen.exe

由於 JIT 編譯器會在呼叫該組件中所定義的個別方法時,將組件的 MSIL 轉換成機器碼,因此這會對執行階段的效能產生不良影響。Because the JIT compiler converts an assembly's MSIL to native code when individual methods defined in that assembly are called, it affects performance adversely at run time. 在大部分情況下,效能稍減是可以接受的。In most cases, that diminished performance is acceptable. 最重要的是,JIT 編譯器產生的程式碼會繫結至觸發編譯的處理序。More importantly, the code generated by the JIT compiler is bound to the process that triggered the compilation. 該程式碼無法跨多個處理序共用。It cannot be shared across multiple processes. 為了允許在多個應用程式的引動過程間共用產生的程式碼,或允許在共用組件集的多個處理序間共用產生的程式碼,Common Language Runtime 支援事先編譯模式。To allow the generated code to be shared across multiple invocations of an application or across multiple processes that share a set of assemblies, the common language runtime supports an ahead-of-time compilation mode. 這個預先編譯模式會使用 Ngen.exe (原生映像產生器) 將 MSIL 組件轉換成機器碼,與 JIT 編譯器相當類似。This ahead-of-time compilation mode uses the Ngen.exe (Native Image Generator) to convert MSIL assemblies to native code much like the JIT compiler does. 不過,Ngen.exe 的作業與 JIT 編譯器的作業有三個不同的地方:However, the operation of Ngen.exe differs from that of the JIT compiler in three ways:

  • 它會事先執行從 MSIL 至機器碼的轉換,而不是在執行應用程式時。It performs the conversion from MSIL to native code before running the application instead of while the application is running.

  • 它會一次編譯整個組件,而非一次一個方法。It compiles an entire assembly at a time, instead of one method at a time.

  • 它會將原生映像快取中產生的程式碼保存為磁碟上的檔案。It persists the generated code in the Native Image Cache as a file on disk.

程式碼驗證Code Verification

做為編譯成機器碼過程的一部分,MSIL 程式碼必須通過驗證程序,除非系統管理員建立的安全性原則允許程式碼略過驗證。As part of its compilation to native code, the MSIL code must pass a verification process unless an administrator has established a security policy that allows the code to bypass verification. 驗證會檢查 MSIL 和中繼資料,以了解該程式碼是否為類型安全,表示它僅存取獲得授權之可存取的記憶體位置。Verification examines MSIL and metadata to find out whether the code is type safe, which means that it accesses only the memory locations it is authorized to access. 類型安全有助於隔離各物件,因此就能免於意外或惡意的損毀。Type safety helps isolate objects from each other and helps protect them from inadvertent or malicious corruption. 它也保證會確實地強制執行程式碼的安全性限制。It also provides assurance that security restrictions on code can be reliably enforced.

可驗證的類型安全程式碼會滿足下列陳述,此為執行階段所仰賴的:The runtime relies on the fact that the following statements are true for code that is verifiably type safe:

  • 類型的參考與正被參考的類型完全相容。A reference to a type is strictly compatible with the type being referenced.

  • 在物件上只叫用適當定義的作業。Only appropriately defined operations are invoked on an object.

  • 這些識別與它們所宣告的一樣。Identities are what they claim to be.

在驗證程序期間,會檢查 MSIL 程式碼以確認程式碼只會使用正確定義的類型來存取記憶體位置和呼叫方法。During the verification process, MSIL code is examined in an attempt to confirm that the code can access memory locations and call methods only through properly defined types. 例如,程式碼不允許以可讓記憶體位置滿溢的方式存取物件欄位。For example, code cannot allow an object's fields to be accessed in a manner that allows memory locations to be overrun. 此外,驗證會檢視程式碼,以判斷 MSIL 是否已經正確產生,因為不正確的 MSIL 可能會違反類型安全規則。Additionally, verification inspects code to determine whether the MSIL has been correctly generated, because incorrect MSIL can lead to a violation of the type safety rules. 驗證程序會讓妥善定義的類型安全程式碼集合通過驗證,它也只會讓類型安全的程式碼通過驗證。The verification process passes a well-defined set of type-safe code, and it passes only code that is type safe. 然而,由於驗證程序的某些限制,某些類型安全程式碼可能無法通過驗證,而某些語言由於設計之故,不會產生可驗證的類型安全程式碼。However, some type-safe code might not pass verification because of some limitations of the verification process, and some languages, by design, do not produce verifiably type-safe code. 如果安全性原則需要類型安全程式碼,但該程式碼沒有通過驗證,則在程式碼執行時會產生例外狀況。If type-safe code is required by the security policy but the code does not pass verification, an exception is thrown when the code is run.

回到頁首Back to top

執行程式碼Running Code

Common Language Runtime 提供基礎結構,啟用 Managed 執行以及可在執行期間使用的服務。The common language runtime provides the infrastructure that enables managed execution to take place and services that can be used during execution. 在可以執行方法之前,必須將其編譯為處理器特定程式碼。Before a method can be run, it must be compiled to processor-specific code. 在初次呼叫時,已經產生 MSIL 的每個方法都會進行 JIT 編譯,然後才會執行。Each method for which MSIL has been generated is JIT-compiled when it is called for the first time, and then run. 下次執行方法時,就會執行現有以 JIT 編譯的機器碼。The next time the method is run, the existing JIT-compiled native code is run. JIT 編譯和接著執行程式碼的過程會不斷重複,直到執行完成為止。The process of JIT-compiling and then running the code is repeated until execution is complete.

在執行期間,Managed 程式碼會接收服務,例如記憶體回收、安全性、與 Unmanaged 程式碼的互通性、跨語言偵錯支援,以及增強的部署和版本控制支援。During execution, managed code receives services such as garbage collection, security, interoperability with unmanaged code, cross-language debugging support, and enhanced deployment and versioning support.

在 Microsoft Windows XPWindows XPWindows VistaWindows Vista中,作業系統載入器會查看 COFF 標頭中的位元,檢查 Managed 模組。In Microsoft Windows XPWindows XP and Windows VistaWindows Vista, the operating system loader checks for managed modules by examining a bit in the COFF header. 所設定的位元代表 Managed 模組。The bit being set denotes a managed module. 如果載入器偵測到 Managed 模組,則會載入 mscoree.dll,而當載入和卸載 Managed 模組映像時, _CorValidateImage_CorImageUnloading 會通知載入器。If the loader detects managed modules, it loads mscoree.dll, and _CorValidateImage and _CorImageUnloading notify the loader when the managed module images are loaded and unloaded. _CorValidateImage 會執行下列動作:_CorValidateImage performs the following actions:

  1. 確定程式碼是有效的 Managed 程式碼。Ensures that the code is valid managed code.

  2. 將映像中的進入點變更為執行階段中的進入點。Changes the entry point in the image to an entry point in the runtime.

在 64 位元的 Windows 中, _CorValidateImage 會將記憶體中的映像從 PE32 格式轉換為 PE32+ 格式,以便進行修改。On 64-bit Windows, _CorValidateImage modifies the image that is in memory by transforming it from PE32 to PE32+ format.

回到頁首Back to top

請參閱See also