CPU雖然是計算機的核心,但光有CPU還是不能干活的,至少還需要有地方來存放機器指令代碼。這就用到了存儲器,有兩種存儲器:外存和內存。
內存(參見圖1-46)通常容量較小,存取數據的速度非常快,但一旦停電後,其中的信息會完全丟失。
外存有許多種,如光盤、U盤和硬盤(參見圖1-47)等,其特點是容量大,存取速度較慢,但停電之後信息仍然存在。
人類寫的程序,經過編譯器轉為機器指令後,一般以文件的方式保存在外存儲器中,當CPU執行程序時,要先把外存儲器中的指令讀入到內存中。內存被分 成很多塊,每塊都有一個惟一的地址,指令就存放在以某個特定的地址(稱為入口地址)開始的內存區域中。CPU從入口地址處取出第一條機器指令,開始執行, 然後再取第二條,依次類推。
圖1-46 內存 圖1-47 硬盤
把一個程序從硬盤上裝入內存執行是一個復雜的過程,這個功能由操作系統實現,開發具體應用程序的軟件工程師不需要自己動手去寫這部分代碼,其過程可參見圖1-48。
從圖1-48可以看到,程序的運行必須依賴於操作系統(如Windows和Linux),而且編譯器生成的程序文件包含的是特定CPU的機器指令。由於不同CPU的機器指令不同,所以,生成的程序不能不加修改地在具有不同種類CPU的計算機上運行。
以這種方式生成的機器指令代碼稱為非托管代碼(UnManaged Code)。非托管代碼不僅不能在不同種類的計算機上執行,而且,在不同的操作系統下也不能執行。比如一個Windows應用程序就無法在Linux下運行,反之亦然。
圖1-49很好地說明了非托管代碼的運行原理。
$False$圖1-48 程序執行過程 圖1-49 非托管代碼運行原理
顯然,如果需要在不同的計算機和操作系統上實現同一功能,就不得不為每種操作系統和計算機各寫一種代碼。這顯然是一種重復且低效的勞動。
程序能不能只寫一次,處處運行?
完全可以,這就是目前非常紅火的Java語言的設計思想。.NET也采用了這種設計思想,而且走得更遠。.NET在架構設計上不僅允許.Net程序在各種操作系統和計算機上運行,而且允許在同一個程序中使用由不同的計算機語言開發出來的軟件組件。
要支持跨平台和跨語言這一特性,軟件工程師寫的程序經過編譯器生成的結果就不能是依賴於操作系統和計算機硬件的機器指令了,而必須是一種中間的、在 所有操作系統和計算機硬件平台上都能執行的代碼,這種代碼Java稱之為ByteCode(字節碼),.Net稱之為MSIL(微軟中間語言)。
程序最終還是要靠CPU執行,所以,Java的ByteCode和.Net的MSIL仍然需要最終被翻譯成CPU能執行的機器指令,這部分功能由一個運行在特定操作系統之上的軟件系統來完成,這個軟件系統稱為VM(Virtual Machine,虛擬機)。
只需要為每種操作系統和特定的硬件平台提供一個虛擬機,就可以讓同樣一個程序不加修改地在不同的操作系統和硬件結構的計算機上運行。
這種運行在虛擬機之上的代碼稱為托管代碼(Managed Code),其運行原理如圖1-50所示。
繞 了這麼大的一個圈子,現在終於可以講明白了,前面章節所介紹的.NET Framework,其實就是一個運行在操作系統Windows之上的軟件虛擬機。使用VS .NET開發出來的程序經過編譯之後,生成的可執行程序實際上包含的只是MSIL指令代碼,這是一種托管代碼,只能運行在.NET虛擬機之上。所以,如果 某台計算機上沒有安裝.NET Framework,就意味著圖1-50中的“虛擬機”一層不存在,.NET應用程序就無法執行。對於非Windows的操作系統,只要上面有.NET虛 擬機,就可以運行.Net程序,不需要重新修改源程序並重新編譯。
提示
在Linux下運行的.Net Framework稱為MONO。這是一個開源的軟件項目。可以到因特網上搜集它的信息。