當前位置:首頁 » 服務存儲 » 內核空間的物理存儲區
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

內核空間的物理存儲區

發布時間: 2022-08-07 04:30:21

A. 物理內存和內核內存是什麼

物理內存就是插到機器上的內存條!!

物理內存好象就是買的內存條

核心內存即內核內存,是操作系統為內核對象分配的內存
核心內存是虛擬內存,自己或系統自動設置。
內存在計算機中的作用很大,電腦中所有運行的程序都需要經過內存來執行,如果執行的程序很大或很多,就會導致內存消耗殆盡。為了解決這個問題, Windows中運用了虛擬內存技術,即拿出一部分硬碟空間來充當內存使用,當內存佔用完時,電腦就會自動調用硬碟來充當內存,以緩解內存的緊張。舉一個例子來說,如果電腦只有128MB物理內存的話,當讀取一個容量為200MB的文件時,就必須要用到比較大的虛擬內存,文件被內存讀取之後就會先儲存到虛擬內存,等待內存把文件全部儲存到虛擬內存之後,跟著就會把虛擬內里儲存的文件釋放到原來的安裝目錄里了。

B. 在x86體系下,進程式控制制塊存放在內核空間的什麼位置

linux驅動程序一般工作在內核空間,但也可以工作在用戶空間。下面我們將詳細解析,什麼是內核空間,什麼是用戶空間,以及如何判斷他們。

Linux簡化了分段機制,使得虛擬地址與線性地址總是一致,因此,Linux的虛擬地址空間也為0~4G.Linux內核將這4G位元組的空間分為兩部分。將最高的1G位元組(從虛擬地址0xC0000000到0xFFFFFFFF),供內核使用,稱為"內核空間".而將較低的3G位元組(從虛擬地址 0x00000000到0xBFFFFFFF),供各個進程使用,稱為"用戶空間)。因為每個進程可以通過系統調用進入內核,因此,Linux內核由系統內的所有進程共享。於是,從具體進程的角度來看,每個進程可以擁有4G位元組的虛擬空間。

Linux使用兩級保護機制:0級供內核使用,3級供用戶程序使用。從圖中可以看出(這里無法表示圖),每個進程有各自的私有用戶空間(0~3G),這個空間對系統中的其他進程是不可見的。最高的1GB位元組虛擬內核空間則為所有進程以及內核所共享。

內核空間中存放的是內核代碼和數據,而進程的用戶空間中存放的是用戶程序的代碼和數據。不管是內核空間還是用戶空間,它們都處於虛擬空間中。

雖然內核空間占據了每個虛擬空間中的最高1GB位元組,但映射到物理內存卻總是從最低地址(0x00000000)開始。對內核空間來說,其地址映射是很簡單的線性映射,0xC0000000就是物理地址與線性地址之間的位移量,在Linux代碼中就叫做PAGE_OFFSET.

內核空間和用戶空間之間如何進行通訊?

內核空間和用戶空間一般通過系統調用進行通信。

如何判斷一個驅動是用戶模式驅動還是內核模式驅動? 判斷的標準是什麼?

用戶空間模式的驅動一般通過系統調用來完成對硬體的訪問,如通過系統調用將驅動的io空間映射到用戶空間等。因此,主要的判斷依據就是系統調用。

內核空間和用戶空間上不同太多了,說不完,比如用戶態的鏈表和內核鏈表不一樣;用戶態用printf,內核態用printk;用戶態每個應用程序空間是虛擬的,相對獨立的,內核態中卻不是獨立的,所以編程要非常小心。等等。

還有用戶態和內核態程序通訊的方法很多,不單單是系統調用,實際上系統調用是個不好的選擇,因為需要系統調用號,這個需要統一分配。

可以通過ioctl、sysfs、proc等來完成。

在進行設備驅動程序,內核功能模塊等系統級開發時,通常需要在內核和用戶程序之間交換信息。Linux提供了多種方法可以用來完成這些任務。本文總結了各種常用的信息交換方法,並用簡單的例子演示這些方法各自的特點及用法。其中有大家非常熟悉的方法,也有特殊條件下方可使用的手段。通過對比明確這些方法,可以加深我們對Linux內核的認識,更重要的是,可以讓我們更熟練駕御linux內核級的應用開發技術。

內核空間(kernel-space) VS 用戶空間(user-space)
作為一個Linux開發者,首先應該清楚內核空間和用戶空間的區別。關於這個話題,已經有很多相關資料,我們在這里簡單描述如下:
現代的計算機體系結構中存儲管理通常都包含保護機制。提供保護的目的,是要避免系統中的一個任務訪問屬於另外的或屬於操作系統的存儲區域。如在IntelX86體系中,就提供了特權級這種保護機制,通過特權級別的區別來限制對存儲區域的訪問。 基於這種構架,Linux操作系統對自身進行了劃分:一部分核心軟體獨立於普通應用程序,運行在較高的特權級別上,(Linux使用Intel體系的特權級3來運行內核。)它們駐留在被保護的內存空間上,擁有訪問硬體設備的所有許可權,Linux將此稱為內核空間。
相對的,其它部分被作為應用程序在用戶空間執行。它們只能看到允許它們使用的部分系統資源,並且不能使用某些特定的系統功能,不能直接訪問硬體,不能直接訪問內核空間,當然還有其他一些具體的使用限制。(Linux使用Intel體系的特權級0來運行用戶程序。)
從安全形度講將用戶空間和內核空間置於這種非對稱訪問機制下是很有效的,它能抵禦惡意用戶的窺探,也能防止質量低劣的用戶程序的侵害,從而使系統運行得更穩定可靠。但是,如果像這樣完全不允許用戶程序訪問和使用內核空間的資源,那麼我們的系統就無法提供任何有意義的功能了。為了方便用戶程序使用在內核空間才能完全控制的資源,而又不違反上述的特權規定,從硬體體系結構本身到操作系統,都定義了標準的訪問界面。關於X86系統的細節,請查閱參考資料1
一般的硬體體系機構都提供一種「門」機制。「門」的含義是指在發生了特定事件的時候低特權的應用程序可以通過這些「門」進入高特權的內核空間。對於IntelX86體系來說,Linux操作系統正是利用了「系統門」這個硬體界面(通過調用int $0x80機器指令),構造了形形色色的系統調用作為軟體界面,為應用程序從用戶態陷入到內核態提供了通道。通過「系統調用」使用「系統門」並不需要特別的許可權,但陷入到內核的具體位置卻不是隨意的,這個位置由「系統調用」來指定,有這樣的限制才能保證內核安全無虞。我們可以形象地描述這種機制:作為一個遊客,你可以買票要求進入野生動物園,但你必須老老實實的坐在觀光車上,按照規定的路線觀光游覽。當然,不準下車,因為那樣太危險,不是讓你丟掉小命,就是讓你嚇壞了野生動物。
出於效率和代碼大小的考慮,內核程序不能使用標准庫函數(當然還有其它的顧慮,詳細原因請查閱參考資料2)因此內核開發不如用戶程序開發那麼方便。
內核空間和用戶空間的相互作用
現在,越來越多的應用程序需要編寫內核級和用戶級的程序來一起完成具體的任務,通常採用以下模式:首先,編寫內核服務程序利用內核空間提供的許可權和服務來接收、處理和緩存數據;然後編寫用戶程序來和先前完成的內核服務程序交互,具體來說,可以利用用戶程序來配置內核服務程序的參數,提取內核服務程序提供的數據,當然,也可以向內核服務程序輸入待處理數據。
比較典型的應用包括: Netfilter(內核服務程序:防火牆)VS Iptable(用戶級程序:規則設置程序);IPSEC(內核服務程序:VPN協議部分)VS IKE(用戶級程序:vpn密鑰協商處理);當然還包括大量的設備驅動程序及相應的應用軟體。這些應用都是由內核級和用戶級程序通過相互交換信息來一起完成特定任務的。
信息交互方法
用戶程序和內核的信息交換是雙向的,也就是說既可以主動從用戶空間向內核空間發送信息,也可以從內核空間向用戶空間提交數據。當然,用戶程序也可以主動地從內核提取數據。下面我們就針對內核和用戶交互數據的方法做一總結、歸納。
信息交互按信息傳輸發起方可以分為用戶向內核傳送/提取數據和內核向用戶空間提交請求兩大類,先來說說:
由用戶級程序主動發起的信息交互。

(1)編寫自己的系統調用
從前文可以看出,系統調用是用戶級程序訪問內核最基本的方法。目前linux大致提供了二百多個標準的系統調用,並且允許我們添加自己的系統調用來實現和內核的信息交換。比如我們希望建立一個系統調用日誌系統,將所有的系統調用動作記錄下來,以便進行入侵檢測。此時,我們可以編寫一個內核服務程序。該程序負責收集所有的系統調用請求,並將這些調用信息記錄到在內核中自建的緩沖里。我們無法在內核里實現復雜的入侵檢測程序,因此必須將該緩沖里的記錄提取到用戶空間。最直截了當的方法是自己編寫一個新系統調用實現這種提取緩沖數據的功能。當內核服務程序和新系統調用都實現後,我們就可以在用戶空間里編寫用戶程序進行入侵檢測任務了,入侵檢測程序可以定時、輪訓或在需要的時候調用新系統調用從內核提取數據,然後進行入侵檢測(具體步驟和代碼參見Linux內核之旅網站電子雜志第四期)。
(2)編寫驅動程序
Linux/UNIX的一個特點就是把所有的東西都看作是文件(every thing is a file)。系統定義了簡潔完善的驅動程序界面,客戶程序可以用統一的方法透過這個界面和內核驅動程序交互。而大部分系統的使用者和開發者已經非常熟悉這種界面以及相應的開發流程了。
驅動程序運行於內核空間,用戶空間的應用程序通過文件系統中/dev/目錄下的一個文件來和它交互。這就是我們熟悉的那個文件操作流程:open() —— read() —— write() —— ioctl() ——close()。(需要注意的是也不是所有的內核驅動程序都是這個界面,網路驅動程序和各種協議棧的使用就不大一致,比如說套介面編程雖然也有open()和close()等概念,但它的內核實現以及外部使用方式都和普通驅動程序有很大差異。)關於這部分的編程細節,請查閱參考資料3、4。
設備驅動程序在內核中要做的中斷響應、設備管理、數據處理等等各種工作這篇文章不去關心,我們把注意力集中在它與用戶級程序交互這一部分。操作系統為此定義了一種統一的交互界面,就是前面所說的open(), read(), write(), ioctl()和close()等等。每個驅動程序按照自己的需要做獨立實現,把自己提供的功能和服務隱藏在這個統一界面下。客戶級程序選擇需要的驅動程序或服務(其實就是選擇/dev/目錄下的文件),按照上述界面和文件操作流程,就可以跟內核中的驅動交互了。其實用面向對象的概念會更容易解釋,系統定義了一個抽象的界面(abstract interface),每個具體的驅動程序都是這個界面的實現(implementation)。
所以驅動程序也是用戶空間和內核信息交互的重要方式之一。其實ioctl, read, write本質上講也是通過系統調用去完成的,只是這些調用已被內核進行了標准封裝,統一定義。因此用戶不必像填加新系統調用那樣必須修改內核代碼,重新編譯新內核,使用虛擬設備只需要通過模塊方法將新的虛擬設備安裝到內核中(insmod上)就能方便使用。關於此方面設計細節請查閱參考資料5,編程細節請查閱參考資料6。
在linux中,設備大致可分為:字元設備,塊設備,和網路介面(字元設備包括那些必須以順序方式,像位元組流一樣被訪問的設備;如字元終端,串口等。塊設備是指那些可以用隨機方式,以整塊數據為單位來訪問的設備,如硬碟等;網路介面,就指通常網卡和協議棧等復雜的網路輸入輸出服務)。如果將我們的系統調用日誌系統用字元型驅動程序的方式實現,也是一件輕松愜意地工作。我們可以將內核中收集和記錄信息的那一部分編寫成一個字元設備驅動程序。雖然沒有實際對應的物理設備,但這並沒什麼問題:Linux的設備驅動程序本來就是一個軟體抽象,它可以結合硬體提供服務,也完全可以作為純軟體提供服務(當然,內存的使用我們是無法避免的)。在驅動程序中,我們可以用open來啟動服務,用read()返回處理好的記錄,用ioctl()設置記錄格式等,用close()停止服務,write()沒有用到,那麼我們可以不去實現它。然後在/dev/目錄下建立一個設備文件對應我們新加入內核的系統調用日誌系統驅動程序。
(3) 使用proc 文件系統
proc是Linux提供的一種特殊的文件系統,推出它的目的就是提供一種便捷的用戶和內核間的交互方式。它以文件系統作為使用界面,使應用程序可以以文件操作的方式安全、方便的獲取系統當前運行的狀態和其它一些內核數據信息。
proc文件系統多用於監視、管理和調試系統,我們使用的很多管理工具如ps,top等,都是利用proc來讀取內核信息的。除了讀取內核信息,proc文件系統還提供了寫入功能。所以我們也就可以利用它來向內核輸入信息。比如,通過修改proc文件系統下的系統參數配置文件(/proc/sys),我們可以直接在運行時動態更改內核參數;再如,通過下面這條指令:
echo 1 > /proc/sys/net/ip_v4/ip_forward
開啟內核中控制IP轉發的開關,我們就可以讓運行中的Linux系統啟用路由功能。類似的,還有許多內核選項可以直接通過proc文件系統進行查詢和調整。
除了系統已經提供的文件條目,proc還為我們留有介面,允許我們在內核中創建新的條目從而與用戶程序共享信息數據。比如,我們可以為系統調用日誌程序(不管是作為驅動程序也好,還是作為單純的內核模塊也好)在proc文件系統中創建新的文件條目,在此條目中顯示系統調用的使用次數,每個單獨系統調用的使用頻率等等。我們也可以增加另外的條目,用於設置日誌記錄規則,比如說不記錄open系統調用的使用情況等。關於proc文件系統得使用細節,請查閱參考資料7。
(4)使用虛擬文件系統
有些內核開發者認為利用ioctl()系統調用往往會似的系統調用意義不明確,而且難控制。而將信息放入到proc文件系統中會使信息組織混亂,因此也不贊成過多使用。他們建議實現一種孤立的虛擬文件系統來代替ioctl()和/proc,因為文件系統介面清楚,而且便於用戶空間訪問,同時利用虛擬文件系統使得利用腳本執行系統管理任務更家方便、有效。
我們舉例來說如何通過虛擬文件系統修改內核信息。我們可以實現一個名為sagafs的虛擬文件系統,其中文件log對應內核存儲的系統調用日誌。我們可以通過文件訪問特普遍方法獲得日誌信息:如
# cat /sagafs/log
使用虛擬文件系統——VFS實現信息交互使得系統管理更加方便、清晰。但有些編程者也許會說VFS 的API 介面復雜不容易掌握,不要擔心2.5內核開始就提供了一種叫做libfs的常式序幫助不熟悉文件系統的用戶封裝了實現VFS的通用操作。有關利用VFS實現交互的方法看參考資料。
(5) 使用內存映像
Linux通過內存映像機制來提供用戶程序對內存直接訪問的能力。內存映像的意思是把內核中特定部分的內存空間映射到用戶級程序的內存空間去。也就是說,用戶空間和內核空間共享一塊相同的內存。這樣做的直觀效果顯而易見:內核在這塊地址內存儲變更的任何數據,用戶可以立即發現和使用,根本無須數據拷貝。而在使用系統調用交互信息時,在整個操作過程中必須有一步數據拷貝的工作——或者是把內核數據拷貝到用戶緩沖區,或只是把用戶數據拷貝到內核緩沖區——這對於許多數據傳輸量大、時間要求高的應用,這無疑是致命的一擊:許多應用根本就無法忍受數據拷貝所耗費的時間和資源。
我們曾經為一塊高速采樣設備開發過驅動程序,該設備要求在20兆采樣率下以1KHz的重復頻率進行16位實時采樣,每毫秒需要采樣、DMA和處理的數據量驚人,如果要使用數據拷貝的方法,根本無法達成要求。此時,內存映像成為唯一的選擇:我們在內存中保留了一塊空間,將其配置成環形隊列供采樣設備DMA輸出數據。再把這塊內存空間映射到在用戶空間運行的數據處理程序上,於是,采樣設備剛剛得到並傳送到主機上的數據,馬上就可以被用戶空間的程序處理。
實際上,內存映射方式通常也正是應用在那些內核和用戶空間需要快速大量交互數據的情況下,特別是那些對實時性要求較強的應用。X window系統的伺服器的虛擬內存區域,就可以被看做是內存映像用法的一個典型例子:X伺服器需要對視頻內存進行大量的數據交換,相對於lseek/write來說,將圖形顯示內存直接映射到用戶空間可以顯著提高效能。
並不是任何類型的應用都適合mmap,比如像串口和滑鼠這些基於流數據的字元設備,mmap就沒有太大的用武之地。並且,這種共享內存的方式存在不好同步的問題。由於沒有專門的同步機制可以讓用戶程序和內核程序共享,所以在讀取和寫入數據時要有非常謹慎的設計以保證不會產生干繞。
mmap完全是基於共享內存的觀念了,也正因為此,它能提供額外的便利,但也特別難以控制。
由內核主動發起的信息交互
在內核發起的交互中,我們最關心和感興趣的應該是內核如何向用戶程序發消息,用戶程序又是怎樣接收這些消息的,具體問題通常集中在下面這幾個方面:內核可否調用用戶程序?是否可以通過向用戶進程發信號來告知用戶進程事件發生?
前面介紹的交互方法最大的不同在於這些方式是由內核採取主動,而不是等系統調用來被動的返回信息的。
(1) 從內核空間調用用戶程序。
即使在內核中,我們有時也需要執行一些在用戶級才提供的操作:如打開某個文件以讀取特定數據,執行某個用戶程序從而完成某個功能。因為許多數據和功能在用戶空間是現有的或者已經被實現了,那麼沒有必要耗費大量的資源去重復。此外,內核在設計時,為了擁有更好的彈性或者性能以支持未知但有可能發生的變化,本身就要求使用用戶空間的資源來配合完成任務。比如內核中動態載入模塊的部分需要調用kmod。但在編譯kmod的時候不可能把所有的內核模塊都訂下來(要是這樣的話動態載入模塊就沒有存在意義了),所以它不可能知道在它以後才出現的那些模塊的位置和載入方法。因此,模塊的動態載入就採用了如下策略:載入任務實際上由位於用戶空間的modprobe程序幫助完成——最簡單的情形是modprobe用內核傳過來的模塊名字作為參數調用insmod。用這種方法來載入所需要的模塊。
內核中啟動用戶程序還是要通過execve這個系統調用原形,只是此時的調用發生在內核空間,而一般的系統調用則在用戶空間進行。如果系統調用帶參數,那將會碰到一個問題:因為在系統調用的具體實現代碼中要檢查參數合法性,該檢查要求所有的參數必須位於用戶空間——地址處於0x0000000——0xC0000000之間,所以如果我們從內核傳遞參數(地址大於0xC0000000),那麼檢查就會拒絕我們的調用請求。為了解決這個問題,我們可以利用set_fs宏來修改檢查策略,使得允許參數地址為內核地址。這樣內核就可以直接使用該系統調用了。
例如:在kmod通過調用execve來執行modprobe的代碼前需要有set_fs(KERNEL_DS):
......
set_fs(KERNEL_DS);

/* Go, go, go... */
if (execve(program_path, argv, envp) < 0)
return -errno;
上述代碼中program_path 為"/sbin/modprobe",argv為{ modprobe_path, "-s", "-k", "--", (char*)mole_name, NULL },envp為{ "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }。

從內核中打開文件同樣使用帶參數的open系統調用,所需的仍是要先調用set_fs宏。

(2) 利用brk系統調用來導出內核數據
內核和用戶空間傳遞數據主要是用get_user(ptr)和put_user(datum,ptr)常式。所以在大部分需要傳遞數據的系統調用中都可以找到它們的身影。可是,如果我們不是通過用戶程序發起的系統調用——也就是說,沒有明確的提供用戶空間內的緩沖區位置——的情況下,如何向用戶空間傳遞內核數據呢?
顯然,我們不能再直接使用put_user()了,因為我們沒有辦法給它指定目的緩沖區。所以,我們要借用brk系統調用和當前進程空間:brk用於給進程設置堆空間的大小。每個進程擁有一個獨立的堆空間,malloc等動態內存分配函數其實就是進程的堆空間中獲取內存的。我們將利用brk在當前進程(current process)的堆空間上擴展一塊新的臨時緩沖區,再用put_user將內核數據導出到這個確定的用戶空間去。
還記得剛才我們在內核中調用用戶程序的過程嗎?在那裡,我們有一個跳過參數檢查的操作,現在有了這種方法,可以另闢蹊徑了:我們在當前進程的堆上擴展一塊空間,把系統調用要用到的參數通過put_user()拷貝到新擴展得到的用戶空間里,然後在調用execve的時候以這個新開辟空間地址作為參數,於是,參數檢查的障礙不復存在了。
char * program_path = "/bin/ls" ;
/* 找到當前堆頂的位置*/
mmm=current->mm->brk;
/* 用brk在堆頂上原擴展出一塊256位元組的新緩沖區*/
ret = brk(*(void)(mmm+256));
/* 把execve需要用到的參數拷貝到新緩沖區上去*/
put_user((void*)2,program_path,strlen(program_path)+1);
/* 成功執行/bin/ls程序!*/
execve((char*)(mmm+2));
/* 恢復現場*/
tmp = brk((void*)mmm);
這種方法沒有一般性(具體的說,這種方法有負面效應嗎),只能作為一種技巧,但我們不難發現:如果你熟悉內核結構,就可以做到很多意想不到的事情!
(3) 使用信號
信號在內核里的用途主要集中在通知用戶程序出現重大錯誤,強行殺死當前進程,這時內核通過發送SIGKILL信號通知進程終止,內核發送信號使用send_sign(pid,sig)常式,可以看到信號發送必須要事先知道進程序號(pid),所以要想從內核中通過發信號的方式非同步通知用戶進程執行某項任務,那麼必須事先知道用戶進程的進程號才可。而內核運行時搜索到特定進程的進程號是個費事的工作,可能要遍歷整個進程式控制制塊鏈表。所以用信號通知特定用戶進程的方法很糟糕,一般在內核不會使用。內核中使用信號的情形只出現在通知當前進程(可以從current變數中方便獲得pid)做某些通用操作,如終止操作等。因此對內核開發者該方法用處不大。
類似情況還有消息操作。這里不羅嗦了。

總結 由用戶級程序主動發起的信息交互,無論是採用標準的調用方式還是透過驅動程序界面,一般都要用到系統調用。而由內核主動發起信息交互的情況不多。也沒有標準的界面,操作大不方便。所以一般情況下,盡可能用本文描述的前幾種方法進行信息交互。畢竟,在設計的根源上,相對於客戶級程序,內核就被定義為一個被動的服務提供者。因此,我們自己的開發也應該盡量遵循這種設計原則。

C. 內核內存包括虛擬內存和物理內存

你好,一般默認情況下是利用C盤的剩餘空間來做虛擬內存的,因此C盤的剩餘空間越大對系統運行就越好,虛擬內存是隨著你的使用而動態地變化的,這樣C盤就容易產生磁碟碎片,影響系統運行速度,所以,最好將虛擬內存設置在其它分區,如D盤中。
右鍵點「我的電腦」,左鍵點「屬性」,點選「高級」選項卡,點「性能」里的「設置」按鈕,再選「高級」選項卡,點下面的「更改」按鈕,所彈出的窗口就是虛擬內存設置窗口,一般默認的虛擬內存是從小到大的一段取值范圍,這就是虛擬內存變化大小的范圍,最好給它一個固定值,這樣就不容易產生磁碟碎片了,具體數值根據你的物理內存大小來定,一般為物理內存的1.5到2倍,如內存為256M,那麼應該設置256*1.5=384M,或者乾脆512M。
2、設置方法如下:
假設內存為256M,虛擬內存放在D盤,先要將默認的清除,保持C盤為選中狀態,單選「無分頁文件(N)」再按「設置」按鈕,此時C盤旁的虛擬內存就消失了,然後選中D盤,單選「自定義大小」,在下面的「初始大小」和「最大值」兩個方框里都添上512,再點一下「設置」按鈕,會看到D盤的旁邊出現了「512-512」的字樣,這樣就說明設置好了,再一路確定,最終,系統會要重新啟動,重啟一下,便完成了設置。
3、注意:虛擬內存只能有一個,只放在一個盤中!

D. Linux的內核空間和用戶空間是如何劃分的(以32位系統為例)

通常32位Linux內核地址空間劃分0~3G為用戶空間,3~4G為內核空間。地址分配如下圖所示

直接映射區:線性空間中從3G開始最大896M的區間,為直接內存映射區,該區域的線性地址和物理地址存在線性轉換關系:線性地址=3G+物理地址。

動態內存映射區:該區域由內核函數vmalloc來分配,特點是:線性空間連續,但是對應的物理空間不一定連續。vmalloc分配的線性地址所對應的物理頁可能處於低端內存,也可能處於高端內存。

永久內存映射區:該區域可訪問高端內存。訪問方法是使用alloc_page(_GFP_HIGHMEM)分配高端內存頁或者使用kmap函數將分配到的高端內存映射到該區域。

固定映射區:該區域和4G的頂端只有4k的隔離帶,其每個地址項都服務於特定的用途,如ACPI_BASE等。

E. 在android系統中,內核被儲存於設備的哪一個分區中

android 系統內核就是Linux,Linux支持虛擬內存(Virtual Mmemory),虛擬內存是指使用磁碟當作RAM的擴展,這樣可用的內存的大小就相應地增大了。內核會將暫時不用的內存塊的內容寫到硬碟上,這樣一來,這塊內存就可用於其它目的。當需要用到原始的內容時,它們被重新讀入內存。這些操作對用戶來說是完全透明的;Linux下運行的程序只是看到有大量的內存可供使用而並沒有注意到時不時它們的一部分是駐留在硬碟上的。當然,讀寫硬碟要比直接使用真實內存慢得多(要慢數千倍),所以程序就不會象一直在內存中運行的那樣快。用作虛擬內存的硬碟部分被稱為交換空間(Swap Space)。

一般,在交換空間中的頁面首先被換入內存;如果此時沒有足夠的物理內存來容納它們又將被交換出來(到其他的交換空間中)。如果沒有足夠的虛擬內存來容納所有這些頁面,Linux就會波動而不正常;但經過一段較長的時間Linux會恢復,但此時系統已不可用了。
有時,盡管有許多的空閑內存,仍然會有許多的交換空間正被使用。這種情況是有可能發生的,例如如果在某一時刻有進行交換的必要,但後來一個佔用很多物理內存的大進程結束並釋放內存時。被交換出的數據並不會自動地交換進內存,除非有這個需要時。此時物理內存會在一段時間內保持空閑狀態。對此並沒有什麼可擔心的,但是知道了是怎麼一回事,也就無所謂了。

許多操作系統使用了虛擬內存的方法。因為它們僅在運行時才需要交換空間,以解決不會在同一時間使用交換空間,因此,除了當前正在運行的操作系統的交換空間,其它的就是一種浪費。所以讓它們共享一個交換空間將會更有效率。
注意:如果會有幾個人同時使用這個系統,他們都將消耗內存。然而,如果兩個人同時運行一個程序,內存消耗的總量並不是翻倍,因為代碼頁以及共享的庫只存在一份。

Linux系統常常動不動就使用交換空間,以保持盡可能多的空閑物理內存。即使並沒有什麼事情需要內存,Linux也會交換出暫時不用的內存頁面。這可以避免等待交換所需的時間:當磁碟閑著,就可以提前做好交換。可以將交換空間分散在幾個硬碟之上。針對相關磁碟的速度以及對磁碟的訪問模式,這樣做可以提高性能。

與訪問物理內存相比,磁碟的讀寫是很慢的。另外,在相應較短的時間內多次讀磁碟同樣的部分也是常有的事。例如,某人也許首先閱讀了一段E-mail消息,然後為了答復又將這段消息讀入編輯器中,然後又在將這個消息拷貝到文件夾中時,使得郵件程序又一次讀入它。或者考慮一下在一個有著許多用戶的系統中 ls命令會被使用多少次。通過將信息從磁碟上僅讀入一次並將其存於內存中,除了第一次讀以外,可以加快所有其它讀的速度。這叫作磁碟緩沖(Disk Buffering),被用作此目的的內存稱為高速緩沖(Buffer Cache)。但是,由於內存是一種有限而又不充足的資源,高速緩沖不可能做的很大(它不可能包容要用到的所有數據)。當緩沖充滿了數據時,其中最長時間不用的數據將被舍棄以騰出內存空間用於新的數據。

對寫磁碟操作來說磁碟緩沖技術同樣有效。一方面,被寫入磁碟的數據常常會很快地又被讀出(例如,原代碼文件被保存到一個文件中,又被編譯器讀入),所以將要被寫的數據放入緩沖中是個好主意。另一方面,通過將數據放入緩沖中,而不是將其立刻寫入磁碟,程序可以加快運行的速度。以後,寫的操作可以在後台完成,而不會拖延程序的執行。

大多數操作系統都有高速緩沖(盡管可能稱呼不同),但是並不是都遵守上面的原理。有些是直接寫(Write-Through):數據將被立刻寫入磁碟(當然,數據也被放入緩存中)。如果寫操作是在以後做的,那麼該緩存被稱為後台寫(Write-Back)。後台寫比直接寫更有效,但也容易出錯:如果機器崩潰,或者突然掉電,緩沖中改變過的數據就被丟失了。如果仍未被寫入的數據含有重要的薄記信息,這甚至可能意味著文件系統(如果有的話)已不完整。

針對以上的原因,出現了很多的日誌文件系統,數據在緩沖區修改後,同時會被文件系統記錄修改信息,這樣即使此時系統掉電,系統重啟後會首先從日誌記錄中恢復數據,保證數據不丟失。當然這些問題不再本文的敘述范圍。

由於上述原因,在使用適當的關閉過程之前,絕對不要關掉電源,Sync命令傾空(Flushes)緩沖,也即,強迫所有未被寫的數據寫入磁碟,可用以確定所有的寫操作都已完成。在傳統的UNIX系統中,有一個叫做update的程序運行於後台,每隔30秒做一次sync操作,因此通常無需手工使用sync命令了。Linux另外有一個後台程序,Bdflush,這個程序執行更頻繁的但不是全面的同步操作,以避免有時sync的大量磁碟I/O操作所帶來的磁碟的突然凍結。

在Linux中,Bdflush是由update啟動的。通常沒有理由來擔心此事,但如果由於某些原因bdflush進程死掉了,內核會對此作出警告,此時你就要手工地啟動它了(/sbin/update)。

緩存(Cache)實際並不是緩沖文件的,而是緩沖塊的,塊是磁碟I/O操作的最小單元(在Linux中,它們通常是1KB)。這樣,目錄、超級塊、其它文件系統的薄記數據以及非文件系統的磁碟數據都可以被緩沖了。緩沖的效力主要是由它的大小決定的。緩沖太小的話等於沒用。它只能容納一點數據,因此在被重用時,所有緩沖的數據都將被傾空。實際的大小依賴於數據讀寫的頻次、相同數據被訪問的頻率。只有用實驗的方法才能知道。

如果緩存有固定的大小,那麼緩存太大了也不好,因為這會使得空閑的內存太小而導致進行交換操作(這同樣是慢的)。為了最有效地使用實際內存,Linux自動地使用所有空閑的內存作為高速緩沖,當程序需要更多的內存時,它也會自動地減小緩沖的大小。

F. Linux進程內存管理

對於包含MMU的處理器而言,Linux系統提供了復雜的存儲管理系統,使得進程所能訪問的內存達到4GB。在Linux系統中,進程的4GB內存空間被分為兩個部分——用戶空間與內核空間。用戶空間的地址一般分布為0~3GB(即PAGE_OFFSET,在Ox86中它等於OxC0000000),這樣,剩下的3~4GB為內核空間,用戶進程通常只能訪問用戶空間的虛擬地址,不能訪問內核空間的虛擬地址。用戶進程只有通過系統調用(代表用戶進程在內核態執行)等方式才可以訪問到內核空間。
每個進程的用戶空間都是完全獨立、互不相乾的,用戶進程各自有不同的頁表。而內核空間是由內核負責映射,它並不會跟著進程改變,是固定的。內核空間的虛擬地址到物理地址映射是被所有進程共享的,內核的虛擬空間獨立於其他程序。
Linux中1GB的內核地址空間又被劃分為物理內存映射區、虛擬內存分配區、高端頁面映射區、專用頁面映射區和系統保留映射區這幾個區域。
對於x86系統而言,一般情況下,物理內存映射區最大長度為896MB,系統的物理內存被順序映射在內核空間的這個區域中。當系統物理內存大於896MB時,超過物理內存映射區的那部分內存稱為高端內存(而未超過物理內存映射區的內存通常被稱為常規內存),內核在存取高端內存時必須將它們映射到高端頁面映射區。Linux保留內核空間最頂部FIXADDR_TOP~4GB的區域作為保留區。
當系統物理內存超過4GB時,必須使用CPU的擴展分頁(PAE)模式所提供的64位頁目錄項才能存取到4GB以上的物理內存,這需要CPU的支持。加入了PAE功能的Intel Pentium Pro及以後的CPU允許內存最大可配置到64GB,它們具備36位物理地址空間定址能力。
由此可見,對於32位的x86而言,在3~4GB之間的內核空間中,從低地址到高地址依次為:物理內存映射區→隔離帶→vmalloc虛擬內存分配器區→隔離帶→高端內存映射區→專用頁面映射區→保留區。