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