淺談操做系統與內存

淺談操做系統與內存

對於計算機的發明,相信你們都有耳聞那個佔地面積按平米算的第一臺計算機。在那個時候,CPU的資源是極其珍貴的,隨着這些年日新月異的發展,一片指甲蓋大小的民用級CPU一秒鐘能執行的指令數能夠達到上億級別。linux

隨着計算能力的增加,芯片外圍的硬件和配套的軟件也是一路高歌,發生了天翻地覆的變化,今天咱們簡單回顧歷史,來看一看操做系統和內存機制的演變,不只要了解它們是怎樣,同時也看看它們爲何會是這樣。程序員


CPU的運行

一說到CPU(Center processing unit),你們都以爲這是很是了不得的東西,咱們的手機電腦都是由它進行核心控制,擁有掌管一切的能力,可是,它真的有傳說中那麼聰明麼?算法

事實並不是如此,CPU惟一的能力其實就是處理二進制數據,CPU的組成是這樣的:編程

  • CPU有三種總線:控制總線,地址總線,數據總線,這些總線統稱爲系統總線,主要用來與外設交換數據。
  • 內部寄存器若干,通常只有幾十個字節,普通寄存器負責傳輸數據,特殊寄存器如PC,SP,LD則控制程序流程。
  • ALU-算數邏輯運算單元,既然是處理數據,固然也就依賴運算單元,這些運算單元只能處理加減乘法,其實嚴格來講,就是處理加法,減和乘是在加法基礎上實現的。

這三個就是早期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使用權(如等待信號量,等待鎖)
  • 時間片機制,每一個任務分配時間片,通常是ms級別的時間,當時間片用完就切換到下一個任務,營造一種全部任務同時運行的假象。

事實上,操做系統每每在基於上述調度算法的基礎上,運行着更復雜的調度算法,好比以優先級爲權重分配時間片,好比任務分組,不一樣的分組有不一樣的調度策略等等....


任務調度的執行原理

上文說到,操做系統的的最先雛形就是容許CPU中存在多個任務,經過某種調度算法來使每一個任務交替運行。

那麼,CPU究竟是怎麼作到這件事的呢?

首先咱們要了解如下概念:時鐘、中斷,程序執行流的切換。

  • 時鐘:是CPU上最重要的部分之一,任何一個CPU都必須有時鐘部分,它提供了CPU上時間的概念,系統不一樣部分之間的交互和同步都要靠時鐘信號來進行同步。通俗來講,就像人類定義了時間的概念,咱們才能夠統一作到準時上下班,相約同一時間去作某事。CPU也是同樣,在進行數據傳輸時,通訊雙方必須統一傳輸單元數據的時間,才能進行同步和數據解析。
  • 中斷:即便是目前很是簡單的單片機,也提供中斷功能。咱們能夠將中斷理解爲CPU中的突發事件須要緊急處理,這時CPU暫停處理本來任務轉去處理中斷,處理完中斷以後再回頭來處理原先的任務。
  • 程序執行流的切換:CPU中通常會有多個寄存器,分爲通用寄存器和特殊寄存器,通用寄存器用來存取CPU處理的數據,而特殊寄存器中須要說起的就是PC指針(程序計數器),SP(棧指針),PC指針中存儲着下一條將要執行的指令地址,而SP指針則指向棧地址。
    在正常狀況下,程序順序運行,PC指針也是按順序裝載須要執行程序的地址,CPU每次執行一條指令都會從PC指針讀取程序執行地址,而後從執行地址上取到數據,執行相應動做,而棧則保存着函數調用過程當中的信息(由於調用完須要返回到調用前狀態)。

在發生中斷的時候,由於須要跳轉去執行中斷服務函數,確定須要更改程序執行流,在單片機上,CPU將會去查中斷向量表,找到須要執行的函數地址裝載到PC指針處,而後保存一些當前運行參數,好比寄存器數據,棧數據,下一個指令週期將會跳轉執行中斷服務函數。

既然程序的執行流能夠由程序員自由控制,只要控制PC指針指向就能夠,那麼咱們也能夠預先定義兩個任務,當一個任務空閒時,直接跳轉執行到另外一個任務,每一個任務的運行參數好比寄存器數據,棧數據,使用的資源等等進行保存,在切換到某個任務時,只要將保存的信息恢復到原來的狀態就能夠繼續運行任務,這種操做方式固然能夠從兩個延伸到多個,這就是操做系統的模型。

一般,保存信息的部分通常使用結構體鏈表,通常被稱爲任務控制塊(每一個操做系統的叫法不同,但實現的思想是同樣的),每一個線程都有獨立的棧空間以保存每一個線程的運行時狀態。

那麼,咱們怎麼知道何時執行另外一個任務呢?這就須要藉助時鐘中斷提供一個時間的概念,任務的運行時間就以這個時鐘中斷做爲度量,具體的作法就是每隔一個週期(一般很是短,1ms、10ms等)產生一次中斷,在中斷程序中檢查是否須要切換任務運行,而切換的緣由就比較多了,好比運行時間到了、等待某項資源自主休眠等等。

事實上,到這裏,你已經瞭解了嵌入式實時系統的運行原理了,好比ucos,freeRTOS之類的,建議去看看相關源代碼,尤爲是ucos,代碼量少且易懂,麻雀雖小五臟俱全。


嵌入式實時操做系統的內存限制

在早期的單片機上,程序運行在物理內存中,也就是說,程序在運行時直接訪問到物理地址,在程序運行開始,將所有程序加載到內存中,全部的數據地址和程序地址就此固定。

在運行多任務系統時,比較直接的辦法也是直接爲每一個任務分配各自須要的內存空間,好比總內存爲100M,task1須要40M,task2須要50M,task3須要20M,那麼最簡單的辦法是給task1分配40M,給task2分配50M,而task3,很差意思,內存不夠了,不容許運行,這樣簡單的分配方式有如下問題:

  • 地址空間不隔離 試想一下,全部程序都訪問物理地址,那麼就存在task1能夠直接訪問到task2任務內存空間的狀況,這就給了一些惡意程序機會來進行一些非法操做,即便是非惡意可是有bug的程序,也可能會致使其餘任務沒法運行,這對於須要安全穩定的的計算機環境的用戶是不能容忍的。
  • 內存使用效率極低 因爲沒有有效的內存管理機制,一般在一個程序執行時,將整個程序裝載進內存中運行,若是咱們要運行task3,內存已經不夠了,其實系統徹底能夠將暫時沒有運行的task2先裝入磁盤中,將task3裝載到內存,當須要運行task2時,再將task2換回,雖然犧牲了一些執行效率,但總歸是能夠支持更多程序運行。
  • 程序地址空間不肯定 須要瞭解的是程序在編譯階段生成的可執行文件中符號地址是連續且肯定的,即便實現了內存數據與磁盤的交換,將暫時不須要的任務放入磁盤而運行其餘任務,程序每次裝入內存時,都須要從內存中分配一段連續內存,這個空間是不肯定的,可是在程序實現過程當中,有些數據每每要求其地址空間是肯定的,這就會給編寫程序帶來很大的麻煩。

虛擬內存機制

那麼怎麼解決這個問題呢?曾經有人說過一句名言:

計算機科學領域的任何問題均可以經過增長一個間接的中間層來解決。

在這裏這個道理一樣適用,後來的操做系統設計者設計了一種新的模型,在內存中增長一層虛擬地址。

面對開發者而言,程序中使用的地址都是虛擬地址,這樣,只要咱們能妥善處理好虛擬地址到物理地址的映射過程,而這個映射過程被看成獨立的一部分存在,就能夠解決上述提到的三個問題:

  • 首先,對於地址隔離,由於程序員操做的是虛擬地址,虛擬地址在最後會轉化爲物理地址,可能程序A訪問的0x8000,轉換到物理地址是0x3000,而程序B一樣訪問0x8000,可是會被轉換到物理地址0x4000,這樣程序中並不知道本身操做的物理地址,也操做不到實際的物理地址,由於虛擬地址的轉換總會將地址映射到不衝突的物理地址上,同時進行檢測,也就無從影響到別的任務執行。
  • 對於內存使用率來講 創建完善的內存管理機制,能夠更方便地進行內存與磁盤數據的交換,將空置的內存利用起來而不增長編程者的負擔。
  • 對於程序空間不肯定 虛擬內存機制完美地解決了這個問題,在直接操做物理地址時,由於內存與磁盤的交換,可能致使函數或者變量地址的變化,原來程序中的數據必須進行更新。
    而引入虛擬內存機制,程序員只操做虛擬地址,函數、變量虛擬地址不變,物理地址可能變化,可是程序員只須要關注虛擬地址就好了,虛擬地址到物理地址的轉換就由內存管理部分負責。

既然增長了一箇中間層,那麼這個中間層最好是由獨立的部分進行管理,實現這個功能的器件就是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中運行。


無系統單線程,嵌入式實時操做系統和桌面操做系統

能夠在單板機上運行桌面操做系統,是否是運行單線程的單片機和嵌入式實時操做系統就能夠拋棄了呢?

從功能實現上來講,單板機確實比單片機強不少,可是資源的增長同時帶來成本的增長,因此在一些成本敏感的應用場合下反而是單片機的天下。

而對於操做系統而言,嵌入式實時操做系統因爲沒有一些臃腫的系統服務,有時反而有着比桌面系統更好的實時性,在實時性要求高的場合更是風生水起,好比無人機、車載系統。並且運行在單片機上,成本上更有優點。

對於嵌入式開發而言,頗有必要了解這三種程序運行方式:無系統單線程,嵌入式實時操做系統,桌面操做系統。

  • 無系統單線程很好理解,程序順序執行,除了發生中斷以後跳轉執行中斷服務函數,通常不會再發生程序執行流的切換,程序直接操做物理地址,經常使用於嵌入式小型設備,如燈、插座開關等等。
  • 嵌入式實時操做系統:支持多線程的併發執行,多任務循環執行,遵循必定的調度算法,程序直接操做物理地址。例如ucos、free rtos,一般也在移植在資源相對較多的單片機上。
  • 桌面操做系統:CPU自帶MMU,因此支持虛擬內存機制,支持多進程和多線程編程,程序操做虛擬地址,在人機交互上有很好的表現。例如windows,linux,經常使用的手機、ipad、服務器、我的電腦。

在單片機上,無系統單線程模式能夠很簡單地切換到嵌入式實時操做系統,進行相應的移植便可。

可是是否能在其上運行桌面操做系統,是否集成MMU是一個決定性的因素。


好了,關於操做系統和內存的討論就到此爲止啦,若是朋友們對於這個有什麼疑問或者發現有文章中有什麼錯誤,歡迎留言

原創博客,轉載請註明出處!

祝各位早日實現項目叢中過,bug不沾身. (完)

相關文章
相關標籤/搜索