對於計算機的發明,相信你們都有耳聞那個佔地面積按平米算的第一臺計算機。在那個時候,CPU的資源是極其珍貴的,隨着這些年日新月異的發展,一片指甲蓋大小的民用級CPU一秒鐘能執行的指令數能夠達到上億級別。linux
隨着計算能力的增加,芯片外圍的硬件和配套的軟件也是一路高歌,發生了天翻地覆的變化,今天咱們簡單回顧歷史,來看一看操做系統和內存機制的演變,不只要了解它們是怎樣,同時也看看它們爲何會是這樣。程序員
一說到CPU(Center processing unit),你們都以爲這是很是了不得的東西,咱們的手機電腦都是由它進行核心控制,擁有掌管一切的能力,可是,它真的有傳說中那麼聰明麼?算法
事實並不是如此,CPU惟一的能力其實就是處理二進制數據,CPU的組成是這樣的:編程
這三個就是早期CPU的主要部件了,那它是怎麼處理數據的呢?windows
系統總線負責與外部的數據交換,將交換的數據暫時放在寄存器中,而後CPU再從寄存器中獲取數據使用算數邏輯運算單元進行運算,必要時將數據寫回。安全
是的,僅此而已,CPU不能直接播放音樂,它也不能生成遊戲界面,只是孜孜不倦地拿數據,處理數據,寫回數據,像個一刻也不停的流水線工人。服務器
上文中咱們提到CPU的內部寄存器,由於是集成在CPU內部,因此速度很是快,可是同時也由於集成度的問題,CPU中通常只有幾十字節的寄存器,這對於數據處理是遠遠不夠的,因此當運行時存儲空間不夠的時候咱們必須有另外一個地方進行存儲,這就是系統內存。多線程
即便都是數據,也分別有不一樣的屬性,好比是否須要掉電保存,數據處理的速率要求。併發
在程序執行時,須要在存儲設備中保存一些運行參數,這部分存儲數據的速率直接決定了程序運行速率,因此對這部分存儲的要求是速度快,同時由於是存儲運行時參數,因此不須要掉電保存。函數
在程序執行以外,須要保存大量的靜態數據,好比用戶數據,文件,這部分數據須要掉電可以保存,且要求可存儲數據量大,因爲訪問並不頻繁,因此對速率要求能夠下降以節省成本。
由此,存儲設備分化出了ram和rom兩大類,ram有速率快,掉電不保存的特性,而rom是速率慢,存儲量大,掉電保存。
ram和rom只是分別對應易失性存儲器和非易失性存儲器的統稱,事實上ram有sram,sdram等等,而rom有eeprom,flash,硬盤等等。
上面說到CPU的做用,可能你開始有疑問了,既然CPU只能處理簡單的數據,那麼它是怎麼處理複雜軟件的運行的呢?
這就是不少人的一個常見誤區,將CPU和MCU,還有單板機搞混了。
MCU(Microcontroller unit):微控制器,又被稱爲單片微型計算機,常被直接稱爲單片機。它一般集成了CPU,rom,ram以及硬件控制器、外圍電路等等,ram和rom的容量有限,接口電路也有限。
單板機:單板機是把微型計算機的整個功能體系電路(CPU、ROM、RAM、輸入/輸出接口電路以及其餘輔助電路)所有組裝在一塊印製電板上,再用印製電路將各個功能芯片鏈接起來,通常來講資源好比主頻、ram&rom容量要比MCU高出一大截。
事實上,在咱們常見的手機電腦中,用戶常說的CPU,事實上指的是單板機。而在嵌入式設備上,常常會使用到單片機。
常見的第二個誤區就是:認爲整個單板機(或者MCU)上只有CPU是可編程元件,其餘部分都是硬件搭建起來的。
事實上,除了CPU,像各類硬件控制器好比gpio、i2c、dma或者硬盤控制器,這些都是可編程器件,只是這些控制器所扮演的都是一個從機角色,而主控是CPU。
CPU經過系統總線與各個控制器之間進行數據交互,經過特定的預約義的指令來控制控制器的行爲:
好比控制gpio的操做,將某個引腳的電平從0設置成1,這樣再配合上繼電器等硬件上的電路,就能夠實現220V電路的控制。
再者是經過控制gpio以經過預約義的控制協議與鏈接在另外一端的設備進行通訊。
又或者是告訴硬盤控制器,CPU須要訪問某些數據,硬盤控制器將數據傳遞給CPU。
CPU就是這樣經過將指令一級級地將數據傳遞給外設,經過在外設處理器中預約義了一些指令字段,外設接收CPU的數據至關於接收到控制指令,以此實現外設的控制。
而CPU自己則只是孜孜不倦地處理數據,反饋數據。
在早期的CPU上,CPU都是順序執行,一個CPU只運行一個程序,這樣形成的問題就是:當程序在等待某個資源或者讀寫磁盤的時候,CPU就處於空閒狀態,這對CPU來講是很是浪費的。因爲CPU的資源很是珍貴,人們不得不想辦法解決這個問題,因此就有人編寫多任務程序:
一個CPU中能夠存在多個任務,一個時刻只容許一個任務運行,當檢測程序檢測到某個任務處於空閒狀態,就切換下一個任務運行。或者是當前任務主動放棄運行權,切換下一個任務運行。
這就是操做系統的原型,檢測程序通常被稱爲調度器,遵循某種調度算法。
調度算法又常被稱爲調度策略,目前的操做系統經常使用的調度策略有兩種:
事實上,操做系統每每在基於上述調度算法的基礎上,運行着更復雜的調度算法,好比以優先級爲權重分配時間片,好比任務分組,不一樣的分組有不一樣的調度策略等等....
上文說到,操做系統的的最先雛形就是容許CPU中存在多個任務,經過某種調度算法來使每一個任務交替運行。
那麼,CPU究竟是怎麼作到這件事的呢?
首先咱們要了解如下概念:時鐘、中斷,程序執行流的切換。
在發生中斷的時候,由於須要跳轉去執行中斷服務函數,確定須要更改程序執行流,在單片機上,CPU將會去查中斷向量表,找到須要執行的函數地址裝載到PC指針處,而後保存一些當前運行參數,好比寄存器數據,棧數據,下一個指令週期將會跳轉執行中斷服務函數。
既然程序的執行流能夠由程序員自由控制,只要控制PC指針指向就能夠,那麼咱們也能夠預先定義兩個任務,當一個任務空閒時,直接跳轉執行到另外一個任務,每一個任務的運行參數好比寄存器數據,棧數據,使用的資源等等進行保存,在切換到某個任務時,只要將保存的信息恢復到原來的狀態就能夠繼續運行任務,這種操做方式固然能夠從兩個延伸到多個,這就是操做系統的模型。
一般,保存信息的部分通常使用結構體鏈表,通常被稱爲任務控制塊(每一個操做系統的叫法不同,但實現的思想是同樣的),每一個線程都有獨立的棧空間以保存每一個線程的運行時狀態。
那麼,咱們怎麼知道何時執行另外一個任務呢?這就須要藉助時鐘中斷提供一個時間的概念,任務的運行時間就以這個時鐘中斷做爲度量,具體的作法就是每隔一個週期(一般很是短,1ms、10ms等)產生一次中斷,在中斷程序中檢查是否須要切換任務運行,而切換的緣由就比較多了,好比運行時間到了、等待某項資源自主休眠等等。
事實上,到這裏,你已經瞭解了嵌入式實時系統的運行原理了,好比ucos,freeRTOS之類的,建議去看看相關源代碼,尤爲是ucos,代碼量少且易懂,麻雀雖小五臟俱全。
在早期的單片機上,程序運行在物理內存中,也就是說,程序在運行時直接訪問到物理地址,在程序運行開始,將所有程序加載到內存中,全部的數據地址和程序地址就此固定。
在運行多任務系統時,比較直接的辦法也是直接爲每一個任務分配各自須要的內存空間,好比總內存爲100M,task1須要40M,task2須要50M,task3須要20M,那麼最簡單的辦法是給task1分配40M,給task2分配50M,而task3,很差意思,內存不夠了,不容許運行,這樣簡單的分配方式有如下問題:
那麼怎麼解決這個問題呢?曾經有人說過一句名言:
計算機科學領域的任何問題均可以經過增長一個間接的中間層來解決。
在這裏這個道理一樣適用,後來的操做系統設計者設計了一種新的模型,在內存中增長一層虛擬地址。
面對開發者而言,程序中使用的地址都是虛擬地址,這樣,只要咱們能妥善處理好虛擬地址到物理地址的映射過程,而這個映射過程被看成獨立的一部分存在,就能夠解決上述提到的三個問題:
既然增長了一箇中間層,那麼這個中間層最好是由獨立的部分進行管理,實現這個功能的器件就是MMU,它接管了程序中虛擬地址和物理地址的轉換,MMU通常直接集成在CPU中,不會以獨立的器件存在。
在經典32位桌面操做系統中,有32條地址線(特殊狀況下可能36條),那麼CPU可直接尋址到的內存空間爲2^32字節,也就是4GB,雖然說內存尋址能夠到4G,可是經常在單板機上 並不會有這麼大的物理內存。
根據實際狀況而不一樣,多是512M或者更少,可是因爲虛擬內存機制的存在,程序看起來可操做的內存就是4GB,由於MMU總會找到與程序中的虛擬地址相對應的物理地址,在內存不夠用時,它就會徵用硬盤中的空間,在linux下安裝系統時會讓你分出一片swap分區,顧名思義,swap分區就是用來內存交換的。
那4GB這麼大的內存,若是不進行組織,在CPU讀寫數據時將會是一場災難,由於要找到一個數據在最壞的狀況下須要遍歷整個內存。
就像一個部隊,總要按照軍、師、旅、團、營、連、排、班來劃分,若是全由總司令管理全部人,那也會是一場災難。
所以,對於內存而言,衍生了分段和分頁機制,根據功能劃分段,而後再細分紅頁,通常一頁是4K,固然,這其中會有根據不一樣業務的差異作一些特別的定製。
它的問題就是即便是隻存儲一個字節,也要用掉一頁的內存,形成必定的浪費。
可是若是將分頁粒度定得過細,將會形成訪問成本的增長,由於在不少時候,進行訪問都是直接使用輪詢機制。並且,就像每本書都有目錄和前言,段和頁的信息都要在系統中進行記錄,分頁更細則表明頁數更多,這部分的開銷也就更多。這也是一種浪費。
就像程序中時間與空間的拉鋸戰,計算機中充滿了妥協。
處理器是否攜帶MMU幾乎徹底成了劃分單片機和單板機的分界線。
帶MMU的處理器直接運行桌面系統,如linux、windows之類的,與不帶MMU的單片機相比,體如今用戶眼前的最大區別就是進程的概念,一個進程就是一個程序的運行實體,使得桌面系統中能夠同時運行多個程序,而每一個程序因爲虛擬機制的存在,看起來是獨佔了整個內存空間。
而不帶MMU的處理器,通常是嵌入式設備,程序直接在物理地址上運行,支持多線程。
從程序的加載執行來講,桌面系統中程序編譯完成以後存儲在文件系統中,在程序被調用執行時由加載器加載到內存中執行。而在單片機中,程序編譯生成的可執行文件通常是直接下載到片上flash(rom的一種)中。
32位單片機的尋址範圍爲4G,因爲不支持虛擬內存技術,通常在總線上鏈接的ram不會太大,因此能夠直接將rom也掛載在總線上,CPU能夠直接經過總線訪問flash上的數據,因此程序能夠直接在片上flash中執行,在運行時只是將數據部分加載到ram中運行。
能夠在單板機上運行桌面操做系統,是否是運行單線程的單片機和嵌入式實時操做系統就能夠拋棄了呢?
從功能實現上來講,單板機確實比單片機強不少,可是資源的增長同時帶來成本的增長,因此在一些成本敏感的應用場合下反而是單片機的天下。
而對於操做系統而言,嵌入式實時操做系統因爲沒有一些臃腫的系統服務,有時反而有着比桌面系統更好的實時性,在實時性要求高的場合更是風生水起,好比無人機、車載系統。並且運行在單片機上,成本上更有優點。
對於嵌入式開發而言,頗有必要了解這三種程序運行方式:無系統單線程,嵌入式實時操做系統,桌面操做系統。
在單片機上,無系統單線程模式能夠很簡單地切換到嵌入式實時操做系統,進行相應的移植便可。
可是是否能在其上運行桌面操做系統,是否集成MMU是一個決定性的因素。
好了,關於操做系統和內存的討論就到此爲止啦,若是朋友們對於這個有什麼疑問或者發現有文章中有什麼錯誤,歡迎留言
原創博客,轉載請註明出處!
祝各位早日實現項目叢中過,bug不沾身. (完)