全面分析CLR與操作系統關系
很久沒有翻譯文章了,不過***眼看到Steven Pratschner的這篇文章時就覺得很值得我們學習。這篇文章在CLR設計為我們講述了CLR與操作系統關系,十分值得一讀。,我會在稍后繼續為大家翻譯后邊的部分,希望我的翻譯可以給大家帶來方便。
CLR與操作系統關系概述
過去幾周,我一直在寫一系列文章,來討論創建.Net Compact Framework CLR時不同的設計結果是如何作出的。在***章中,我討論影響設計的環境因素,并提供CLR內存管理的概述。下面幾章我們將詳細討論JIT編譯器、垃圾回收和類裝入器的主要設計思路,還有分析Compact Framework 應用程序內存使用的信息。貫穿這個系列,我將著重討論創建Compact Framework CLR時的設計決定,這些設計與.Net Framework CLR的設計有很大不同。
表面上看起來,.Net Compact Framework是微軟.Net Framework運行時環境的一個直接移植。但在設計的層次上,這兩個產品的相似其實是有意為之,因為這樣會提供相當的好處。Compact Framework和.Net Framework有相同的編程模型,使用相同的文件格式,共享相同的編譯器等等。兩個編程環境如此相似的主要好處是,開發者只要學習一個編程環境,就可以方便地在另一個環境上編程。例如,如果開發者熟悉.Net Framework,他幾乎不需要花時間就可以學會使用.Net Compact Framework開發設備應用程序。
無論表面是如何類似,當你深入內部,你就會發現Compact Framework的實現,尤其是CLR組件,與桌面版本的實現完全不同。無須驚訝,Compact Framework的運行環境直接影響著它內部關鍵組件的架構。兩個主要的環境因素影響了Compact Framework CLR的設計,***是CLR需要運行在少量的內存環境中,第二是需要方便地跨越處理器和操作系統。這個系列文章,通過了解對設計產生影響的約束條件,來討論CLR的內部工作機制。通過這個系列我將指出CLR的哪些設計做了不同于桌面版本的修改,使托管代碼能夠運行在內存受限的環境中。理解CLR的內部機制看起來是一個深奧的話題,但是對于你程序下面的平臺如何工作有一個清晰的了解,會幫助你理解你的應用程序是如何使用設備的資源,也會幫你判斷內存管理或性能相關的問題。
Compact Framework運行在許多不同的操作系統上,但是大部分是安裝在Windows CE上的。讓我們首先來了解一下Windows CE的內存機制。理解操作系統提供給Compact Framework的服務,將幫助我們理解Compact Framework團隊在構建CLR時所作出的決定。The Windows CE Memory Model作為一個32位操作系統,Windows CE可以尋址4GB的虛擬地址空間,這方面和桌面版Windows是一致的。事實上,內存空間的劃分對于Windows CE應用程序架構是有直接影響的。為了解決Windows CE應用程序訪問內存的問題,每個應用程序只能操作32MB的虛擬地址空間。內存可以被分配到這32MB空間之外,但是這些內存是設備上所有應用程序共享的,這些分配的內存不是應用程序私有的。我們在這里只對Windows CE的內存模型進行一個簡單介紹,使我們能夠理解Compact Framework是如何訪問內存的。關于Windows CE內存模型更詳細的描述可以參考Doug Boling的《Programming Windows CE》(中文版名稱《Windows CE程序設計》)。
下面的圖描述了Windows CE應用程序可用的內存區域。
CLR與操作系統關系Figure 1
Memory available to Windows CE applications正如我們所看到的,當程序運行時,會用到三個內存空間區域。System Code Space.裝載系統DLL的只讀代碼頁,比如coredll.dll。這是每個設備的系統代碼空間,所以所有應用程序共享該代碼頁。如果需要,Windows CE可以交換這個內存區域到存儲設備以壓縮空間。
Per-Process Address Space.每個Windows CE進程被分配了32MB的虛擬內存。每個線程的棧地址空間、應用程序可執行文件的代碼頁和任何堆分配和使用的空間都存儲在這個空間中。
High Memory Area.這1GB的高段內存區域為大量的虛擬內存請求提供了虛擬地址空間。任何對VirtulaAlloc的調用請求的虛擬內存空間將被分配到這部分空間中。另外,所有的內存映射文件將被存儲在高段內存中。所有存儲在高地址內存區域中的數據對設備上的所有應用程序可見。如果需要,Windows CE可以將將高地址內存區域交換分頁到存儲設備中。
當程序運行時,.Net Compact Framework從這三個區域中獲取需要的內存。正如我們所見,為了給托管應用程序的開發者提供***體驗,Compact Framework管理每個進程的地址空間。.NET Compact Framework Memory Management Basics提高開發者生產力是促使.Net Framework和.Net Compact Framewok被廣泛采用的主要原因。對于CLR提高開發者生產力的討論經常圍繞著自動內存管理(垃圾收集)、進程獨立等話題展開。Compact Framework除了明確提供了這些功能外,也提供了更多幫助開發者提高移動設備程序開發生產力的更多功能。特別是.Net Compact Framework CLR代替開發者管理每個進程的32MB虛擬內存空間。所以開發者就不必為他們的程序在32MB空間中分配或釋放內存而擔心了。Compact Framework使編寫內存受限設備上的應用程序變得簡單。我們將看到,在這個系列文章中,許多構建.Net Compact Framework CLR的關鍵設計決定就是為了有效地管理每個進程32MB的虛擬內存空間。Windows CE將每個進程限制到一個小的虛擬地址空間中,而Compact Framework團隊所要做的事情就是設計一個平臺,讓應用程序在給定的空間中運行得更好。
在描述允許在內存受限設備上的設計細節前,我們需要先來看一下,當執行一個托管程序時,操作系統和CLR創建的所有運行時數據。在我討論完運行一個程序需要的數據種類后,我將告訴大家CLR會將哪些運行時數據分配到Windows CE的哪個內存區域中去。我們首先來考慮“Hello World”程序運行時,運行時數據的哪些種類需要內存。
- using System;
- using System.ComponentModel;
- using System.Drawing;
- using System.Text;
- using System.Windows.Forms;
- namespace HelloDevice
- {
- public class Form1 : Form
- {
- private MainMenu mainMenu1;
- private Label label1;
- public Form1()
- {
- InitializeComponent();
- }
- private void InitializeComponent()
- {
- this.mainMenu1 = new System.Windows.Forms.MainMenu();
- this.label1 = new System.Windows.Forms.Label();
- // Position the label
- this.label1.Location = new System.Drawing.Point(64, 81);
- this.label1.Size = new System.Drawing.Size(100, 20);
- this.label1.Text = "Hello Device!";
- // Size the form
- this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
- this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
- this.ClientSize = new System.Drawing.Size(240, 268);
- this.Controls.Add(this.label1);
- thisthis.Menu = this.mainMenu1;
- this.MinimizeBox = false;
- this.Text = "Simple App";
- }
- }
- static class Program
- {
- static void Main()
- {
- Application.Run(new Form1());
- }
- }
- }
正如你所看到的,這個程序創建了一個帶有“Hello Device!”字樣的Label控件的窗體。我總結出該程序需要使用內存的六種情況。
Native code pages for the CLR dlls.Compact Framework CLR由兩個DLL組成,分別是mscoree.dll和mscoree2_0.dll。這兩個DLL連同Compact Framework的Windows Forms實現Nativenetcfagl2_0.dll,被成為系統DLL。因此這些DLL的代碼被加載到system code space。Application and Class Library assemblies.CLR必須將應用程序和它需要的類庫的所有IL代碼加載到內存中,在產生相應的本地代碼指令或類加載器展開該類型的數據結構時,訪問需要的元數據時,使JIT編譯器可以訪問到IL。程序集除了包含“Hello World”代碼外,mscorlib所需要的IL還包括System、System.Windows.Forms和System.Drawing。如果需要,包含這些程序集的文件將被內存映射到高位內存區域中。
JIT-compiled native code.當一個應用程序被執行時,每個方法被訪問時,JIT編譯器將被調用,生成本地代碼。本地代碼將被存儲在進程虛擬地址空間的一個buffer里。Allocated reference types.上面分配引用類型的列表中,除了主窗體本身外,還有MainMenu、Label、Point和Size的實例被創建。更多類型在類庫實例化時被創建。所有引用類型所需要的內存來自垃圾收集堆。GC堆是應用程序自己擁有的堆,存儲在應用程序指定的地址空間中。In-memory representation of type metadata.在執行一個程序時需要用到類和方法,CLR從程序集拷貝中讀取他們的元數據,并將它們映射到高位地址空間中。元數據在使用時產生類和方法的內存中表示(in-memory representation)。該表示被存儲在AppDomain堆中。AppDomain堆被存儲在每個進程的虛擬地址空間中。
Miscellaneous allocations.除了上面討論到的這些內存分配類型外,CLR還會在運行程序時產生一小部分附加數據。這類數據包括JIT編譯器用來判斷一個方法是否已經被編譯的stub和其他短暫數據元素。
現在我們可以看到運行托管程序需要用到的數據種類,讓我們將它們映射回Windows CE內存模型中去。圖2表示的就是每種運行時數據種類被存儲到Windows CE內存的哪個區域中。
CLR與操作系統關系Figure 2
The mapping between Compact Framework memory allocations and the Windows CE memory model.根據圖2,最重要的是了解哪些內存是分配在每個進程的空間中,而哪些是被所有進程共享。回到前邊我們對Windows CE內存模型的討論,我們知道,被加載到系統代碼空間中的代碼頁和所有在高位內存地址空間上的內存分配都是被所有應用程序共享的,而在每個進程空間中的內存分配都是該進程私有的。因為進程中的分配不能共享,如何使用每個進程32MB的虛擬地址空間就是一個十分重要的事情。所以我們決定CLR將jitted代碼、引用類型、in-memory type representations和其他小的內存分配都放在進程空間內。更多關于進程堆尺寸的信息可以參考Mike Zintel的Blog Advanced Compact Framework Memory Management。
現在我們討論了基礎話題,下一文我們將討論.Net Compact Framework JIT編譯器的一些基本設計思想。
【編輯推薦】