編譯器、虛擬機、操作系統,到底哪個更難?
?編譯器、虛擬機、操作系統,到底哪個更難?
實際上,除了MATLAB這樣的數學軟件之外,肯定是編譯器更難!
虛擬機和操作系統更多的是麻煩,工作量大,而不是難。
1、虛擬機
什么是虛擬機?
能夠運行字節碼的程序,就是虛擬機。
CPU的機器碼就是一種字節碼,它是直接在硬件上跑的,由硬件的數字電路來保證它的運行。
但是虛擬機是由軟件程序來保證字節碼的運行的。
軟件程序是高級語言寫的,可以寫非常上層的邏輯,實現起來比數字電路簡單得多。
到了字節碼(機器碼)這個層面,邏輯已經非常簡單了,遠不如高級語言的源代碼復雜。
讓字節碼運行起來,實際上比編譯器生成字節碼更簡單:
因為生成字節碼是編碼,而讓字節碼運行是解碼,任何時候都是編碼比解碼更復雜。
編碼,需要把雜亂的信息整理成有序的。
解碼,只需要把有序的信息順序讀出來就行。
所以,H264編碼的CPU消耗,遠比H264解碼更大!
如果字節碼類似RISC架構的機器碼(例如ARM),那么每4字節就是一條指令,指令里的每一位做什么都是固定的。
所以,虛擬機的代碼就是這樣的:
這種程序很難嗎?
不難。
機器碼的邏輯是特別簡單的,比高級語言的代碼簡單得多!
尤其是RISC架構的,更是比x64的機器碼還簡單。
x64的機器碼因為長度不固定,解釋起來要一個字節一個字節的分析,稍微復雜一點,但復雜度也遠不如高級語言的源代碼!
qemu復雜,是因為它要模擬多個型號的CPU。
如果只是給字節碼實現一個跨平臺的虛擬機,并不難。
把java源代碼變成字節碼的過程,遠比讓java字節碼運行起來,要難得多:
前者是編譯器,后者是虛擬機。
2、操作系統
如果只是讓OS內核在CPU上跑起來,大概只需要5000-8000行的C代碼!
Linux 0.01版(即第一個Linux版本)的代碼量也就在8000行左右。
Linux 0.11版,大約不到2萬行。
與編譯器比起來,操作系統只是更麻煩!
因為要支持的驅動模塊很多、要支持的文件系統很多、要支持的網絡協議很多,這些模塊的代碼都是工作量?
但是,麻煩不等于難!
8000行代碼的OS內核(例如Linux 0.01),只需要實現進程管理、內存管理、控制臺管理、鍵盤驅動、硬盤驅動,另外支持一種簡單的文件系統,就可以跑得起來。
這樣的OS內核實際上已經很完善了?
剩下的都是在文件系統的底下添加驅動模塊、網絡協議模塊。
按照unix一切皆是文件的設計哲學,外設的驅動模塊和TCP/IP協議,都是隸屬于文件系統的子模塊。
shell(命令解釋器)不屬于OS內核,而是一個用來解釋命令的用戶態程序。
當然,shell對系統的使用來說是必需的。
在文件系統的API基礎上,實現列目錄、創建目錄、創建文件之類的功能并不難。
當然,這些命令實現起來的工作量,比讓一個8000行的OS內核運行起來還大。
3、編譯器
光一個語法分析就可能超過1萬行!
如果語法像C++那么復雜,那語法分析的代碼量更大。
(如果用第三方的正則表達式庫的話,第三方庫的代碼也沒有低于1萬行的)
而且編譯器的實現中有一些非常別扭的地方,例如C++的如下代碼:
兩個> >之間必須有一個空格,否則g++是會報錯的。
之所以會這樣是鍵盤上的符號太少了,而C++的語法太復雜,在編碼上實在應付不過來了。
另外,編譯器的后端也有一些非常復雜的模塊,例如:指針分析、自動內存管理、循環分析、寄存器分配、goto的處理,等等。
還有一種是并行分析:
顯然,N個源位置與N個目的位置是不可能相同的,所以它可以并行復制數據。
人一眼就可以看出來源位置與目的位置的數組讀寫是不相關的,但用代碼怎么判斷?
要用整數線性規劃。
運籌學上有這一章,龍書(編譯原理)里也有提到,我也曾經學過但都忘了?
虛擬機和操作系統真只是工作量大,論難度還是編譯器和MATLAB!
我的gitee上也有一個bochs上的內核demo,有興趣的可以看看,實現起來比scf簡單多了。
scf編譯器的后端只加了必需的模塊,都寫了4萬行代碼。