linux與uclinux 記憶體管理(1)

來源:互聯網
上載者:User

應該說uClinux同標準Linux的最大區別就在於記憶體管理,同時也由於uClinux的記憶體管理引發了一些標準Linux所不會出現的問題。本文將把uClinux記憶體管理同標準Linux的那記憶體管理部分進行比較分析。
標準Linux使用的虛擬儲存空間技術
標準Linux使用虛擬儲存空間技術,這種技術用於提供比電腦系統中實際使用的實體記憶體大得多的記憶體空間。使用者將感覺到好像程式可以使用非常大的記憶體空間,從而使得編程人員在寫程式時不用考慮電腦中的實體記憶體的實際容量。

為了支援虛擬儲存管理器的管理,Linux系統採用分頁(paging)的方式來載入進程。所謂分頁既是把實際的儲存空間分割為相同大小的段,例如每個段1024個位元組,這樣1024個位元組大小的段便稱為一個頁面(page)。
虛擬儲存空間由儲存空間管理機制及一個大容量的快速硬碟儲存空間支援。它的實現基於局部性原理,當一個程式在運行之前,沒有必要全部裝入記憶體,而是僅將那些當前要啟動並執行那些部分頁面或段裝入記憶體運行(copy-on-write),其餘暫時留在硬碟上程式運行時如果它所要訪問的頁(段)已存在,則程式繼續運行,如果發現不存在的頁(段),作業系統將產生一個頁錯誤(page fault),這個錯誤導致作業系統把需要啟動並執行部分載入到記憶體中。必要時作業系統還可以把不需要的記憶體頁(段)交換到磁碟上。利用這樣的方式管理儲存空間,便可把一個進程所需要用到的儲存空間以化整為零的方式,視需求分批載入,而核心程式則憑藉屬於每個頁面的頁碼來完成定址各個儲存空間區段的工作。
標準Linux是針對有記憶體管理單元的處理器設計的。在這種處理器上,虛擬位址被送到記憶體管理單元(MMU),把虛擬位址映射為物理地址。
通過賦予每個任務不同的虛擬--物理地址轉換映射,支援不同任務之間的保護。地址轉換函式在每一個任務中定義,在一個任務中的虛擬位址空間映射到實體記憶體的一個部分,而另一個任務的虛擬位址空間映射到實體儲存體器中的另外地區。電腦的儲存嵌入式管理單元(MMU)一般有一組寄存器來標識當前啟動並執行進程的轉換表。在當前進程將CPU放棄給另一個進程時(一次環境切換),核心通過指向新進程地址轉換表的指標載入這些寄存器。MMU寄存器是有特權的,只能在核心態才能訪問。這就保證了一個進程只能訪問自己使用者空間內的地址,而不會訪問和修改其它進程的空間。當可執行檔被載入時,載入器根據預設的ld檔案,把程式載入到虛擬記憶體的一個空間,因為這個原因實際上很多程式的虛擬位址空間是相同的,但是由於轉換函式不同,所以實際所處的記憶體地區也不同。而對於多進程管理當處理器進行進程切換並執行一個新任務時,一個重要部分就是為新任務切換任務轉換表。我們可以看到Linux系統的記憶體管理至少實現了以下功能:
運行比記憶體還要大的程式。理想情況下應該可以運行任意大小的程式
◇可以運行只載入了部分的程式,縮短了程式啟動的時間
◇可以使多個程式同時駐留在記憶體中提高CPU的利用率
◇可以運行重定位程式。即程式可以方於記憶體中的任何一處,而且可以在執行過程中移動。
◇寫機器無關的代碼。程式不必事先約定機器的配置情況。
◇減輕程式員分配和管理記憶體資源的負擔。
◇可以進行共用--例如,如果兩個進程運行同一個程式,它們應該可以共用程式碼的同一個副本。
◇提供記憶體保護,進程不能以非授權方式訪問或修改頁面,核心保護單個進程的資料和代碼以防止其它進程修改它們。否則,使用者程式可能會偶然(或惡意)的破壞核心或其它使用者程式。
虛存系統並不是沒有代價的。記憶體管理需要地址轉換表和其他一些資料結構,留給程式的記憶體減少了。地址轉換增加了每一條指令的執行時間,而對於有額外記憶體操作的指令會更嚴重。當進程訪問不在記憶體的頁面時,系統發生失效。系統處理該失效,並將頁面載入到記憶體中,這需要極耗時間的磁碟I/O操作。總之記憶體管理活動佔用了相當一部分cpu時間(在較忙的系統中大約佔10%)。
uClinux針對NOMMU的特殊處理
對於uClinux來說,其設計針對沒有MMU的處理器,即uClinux不能使用處理器的虛擬記憶體管理技術(應該說這種不帶有MMU的處理器在嵌入式裝置中相當普偏)。uClinux仍然採用儲存空間的分頁管理,系統在啟動時把實際儲存空間進行分頁。在載入應用程式時程式分頁載入。但是由於沒有MMU管理,所以實際上uClinux採用實儲存空間管理原則(real memeory management)。這一點影響了系統工作的很多方面。
uClinux系統對於記憶體的訪問是直接的,(它對地址的訪問不需要經過MMU,而是直接送到地址線上輸出),所有程式中訪問的地址都是實際的物理地址。作業系統對記憶體空間沒有保護(這實際上是很多嵌入式系統的特點),各個進程實際上共用一個Runspace(沒有獨立的地址轉換表)。
一個進程在執行前,系統必須為進程分配足夠的連續地址空間,然後全部載入主儲存空間的連續空間中。與之相對應的是標準Linux系統在分配記憶體時沒有必要保證實際實體儲存體空間是連續的,而只要保證虛存地址空間連續就可以了。另外一個方面程式載入地址與預期(ld檔案中指出的)通常都不相同,這樣relocation過程就是必須的。此外磁碟交換空間也是無法使用的,系統執行時如果缺少記憶體將無法通過磁碟交換來得到改善。
uClinux對記憶體的管理減少同時就給開發人員提出了更高的要求。如果從易用性這一點來說,uClinux的記憶體管理是一種倒退,退回了到了UNIX早期或是Dos系統時代。開發人員不得不參與系統的記憶體管理。從編譯核心開始,開發人員必須告訴系統這塊開發板到底擁有多少的記憶體(假如你欺騙了系統,那將在後面運行程式時受到懲罰),從而系統將在啟動的初始化階段對記憶體進行分頁,並且標記已使用的和未使用的記憶體。系統將在運行應用時使用這些分頁記憶體。
由於應用程式載入時必須分配連續的地址空間,而針對不同硬體平台的可一次成塊(連續地址)分配記憶體大小限制是不同(目前針對ez328處理器的uClinux是128k,而針對coldfire處理器的系統記憶體則無此限制),所以開發人員在開發應用程式時必須考慮記憶體的分配情況並關注應用程式需要Runspace的大小。另外由於採用實儲存空間管理原則,使用者程式同核心以及其它使用者程式在一個地址空間,程式開發時要保證不侵犯其它程式的地址空間,以使得程式不至於破壞系統的正常工作,或導致其它程式的運行異常。
從記憶體的訪問角度來看,開發人員的權利增大了(開發人員在編程時可以訪問任意的地址空間),但與此同時系統的安全性也大為下降。此外,系統對多進程的管理將有很大的變化,這一點將在uClinux的多進程管理中說明。
雖然uClinux的記憶體管理與標準Linux系統相比功能相差很多,但應該說這是嵌入式裝置的選擇。在嵌入式裝置中,由於成本等敏感因素的影響,普偏的採用不帶有MMU的處理器,這決定了系統沒有足夠的硬體支援實現虛擬儲存管理技術。從嵌入式裝置實現的功能來看,嵌入式裝置通常在某一特定的環境下運行,只要實現特定的功能,其功能相對簡單,記憶體管理的要求完全可以由開發人員考慮。
標準Linux系統的進程、線程
進程:進程是一個運行程式並為其提供執行環境的實體,它包括一個地址空間和至少一個控制點,進程在這個地址空間上執行單一指令序列。進程地址空間包括可以訪問或引用的記憶體單元的集合,進程式控制制點通過一個一般稱為程式計數器(program counter,PC)的硬體寄存器控制和跟蹤進程指令序列。
fork:由於進程為執行程式的環境,因此在執行程式前必須先建立這個能"跑"程式的環境。Linux系統提供系統調用拷貝現行進程的內容,以產生新的進程,調用fork的進程稱為父進程;而所產生的新進程則稱為子進程。子進程會承襲父進程的一切特性,但是它有自己的資料區段,也就是說,儘管子進程改變了所屬的變數,卻不會影響到父進程的變數值。
父進程和子進程共用一個程式段,但是各自擁有自己的堆棧、資料區段、使用者空間以及進程式控制制塊。換言之,兩個進程執行的程式碼是一樣的,但是各有各的程式計數器與自己的私人資料。
當核心收到fork請求時,它會先查核三件事:首先檢查儲存空間是不是足夠;其次是進程表是否仍有空缺;最後則是看看使用者是否建立了太多的子進程。如果上述說三個條件滿足,那麼作業系統會給子進程一個進程識別碼,並且設定cpu時間,接著設定與父進程共用的段,同時將父進程的inode拷貝一份給子進程運用,最終子進程會返回數值0以表示它是子進程,至於父進程,它可能等待子進程的執行結束,或與子進程各做個的。
exec系統調用:該系統調用提供一個進程去執行另一個進程的能力,exec系統調用是採用覆蓋舊有進程儲存空間內容的方式,所以原來程式的堆棧、資料區段與程式段都會被修改,只有使用者區維持不變。
vfork 系統調用:由於在使用fork時,核心會將父進程拷貝一份給子進程,但是這樣的做法相當浪費時間,因為大多數的情形都是程式在調用fork後就立即調用 exec,這樣剛拷貝來的進程地區又立即被新的資料覆蓋掉。因此Linux系統提供一個系統調用vfork,vfork假定系統在調用完成vfork後會馬上執行exec,因此vfork不拷貝父進程的頁面,只是初始化私人的資料結構與準備足夠的分頁表。這樣實際在vfork調用完成後父子進程事實上共用同一Block Storage器(在子進程調用exec或是exit之前),因此子進程可以更改父進程的資料及堆棧資訊,因此vfork系統調用完成後,父進程進入睡眠,直到子進程執行exec。當子進程執行exec時,由於exec要使用被執行程式的資料,代碼覆蓋子進程的儲存地區,這樣將產生防寫保護錯誤(do_wp_page)(這個時候子進程寫的實際上是父進程的儲存地區),
這個錯誤導致核心為子進程重新分配儲存空間。當子進程正確開始執行後,將喚醒父進程,使得父進程繼續往後執行。
uClinux的多進程處理
uClinux沒有mmu管理儲存空間,在實現多個進程時(fork調用產生子進程)需要實現資料保護。
uClinux 的fork和vfork:uClinux的fork等於vfork。實際上uClinux的多進程管理通過vfork來實現。這意味著uClinux系統 fork調用完程後,要麼子進程代替父進程執行(此時父進程已經sleep)直到子進程調用exit退出,要麼調用exec執行一個新的進程,這個時候將產生可執行檔的載入,即使這個進程只是父進程的拷貝,這個過程也不能避免。當子進程執行exit或exec後,子進程使用wakeup把父進程喚醒,父進程繼續往下執行。
uClinux的這種多進程實現機制同它的記憶體管理緊密相關。uClinux針對nommu處理器開發,所以被迫使用一種 flat方式的記憶體管理員模式,啟動新的應用程式時系統必須為應用程式分配儲存空間,並立即把應用程式載入到記憶體。缺少了MMU的記憶體重新對應機制,uClinux必須在可執行檔載入階段對可執行檔reloc處理,使得程式執行時能夠直接使用實體記憶體。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.