1、硬件角度
大家都曾經看過那個紙上打孔,記錄數據的圖片。
后來都知道出現了內存器,我們執行指令分為加載+運行。
最開始的程序運行時只能跑一個進程的,那就不需要復雜的內存管理,把我弄到固定的位置,然后這片區域都是我的。而且有多大的內存我就用多大的,一旦我進程想用的內存比擁有的物理內存大的時候,崩了就完事了。
特點:單進程 單操作系統 直接使用物理內存
這樣的問題隨著時代的發展問題就來了。
問題一 :單進程用不完資源那不是浪費?
問題二 :我要是物理內存不夠,又沒錢升級硬件怎么辦?
問題三 :因為我的軟件直接操作接觸的物理內存,這個和硬件靠的太近,我們都知道移植性就查了?
隨著發展單進程肯定是不符合要求的,那么怎么辦?多進程(腦子里先把進程調度的事情放下,focu內存方面)。
多進程之間的這個內存怎么處理,總不能讓騰訊的數據訪問到快播的吧,想象你正在看劇,突然內容變成了學習內容,怕怕。為了解決這個問題,在操作系統編譯的時候主存劃分了很多的靜態分區。有進程的時候,你就看看哪里能放下你,你去那里待著。
于是問題又來了
1、程序大小那不是必須和分區匹配,起碼不能比分區小
2、這個進程的數目那就是固定了啊,那不是買電腦還得多一個電腦能跑多少個進程的參數
3、地址空間固定,進程不能膨脹啊。(想想咱們平時LOL,不運行的時候幾個G,運行起來幾百個,那肯肯定是玩不了了)
4、進程之間的邊界真的能控制的很好嗎?現在這么完備的內存管理下還經常出現內存踩踏時間。
解決方法就是前輩們整了個動態的分區,就是給操作系統整一個分區,剩下的有進程時,需要多大分割多大。這樣一整,敏感的你就知道了,分割多了,那不是內存的這個空洞就多了,碎片就多了,那咋整呢。得規整內存,只能遷移進程了,遷移進程你不可能做,只能操作系統了,而這個過程很消耗時間(自己磁盤整理過的都知道哈),需要大量數據的換入換出。尤其是在進程運行的時候內存不夠了,然后你得去遷移,等個一個小時,電腦我都想砸了。
遷移只有這個進程的位置也變了,這個尋址方式就算是相對尋址,那個相對的對象總是絕對的,因此程序編寫你就說頭疼不。(兩數之和已經夠頭疼了,還有心情去管理內存重定位)
同時當這個程序是惡意的,那我不是就可以為所欲為,因為大家都是直接對應的物理內存,我偏不去我該去的地方,我就在你工作的時候來騷擾你一下,你就說怕不怕。
于是這幾個問題:
內存保護、內存運行重定位、使用效率低下無法忍受懶惰是催促科技進步的源動力
1、解決辦法 level1 - 分段機制
為了解決進程間內存保護的問題,提出了虛擬內存。通過增加一層虛擬內存,進程訪問虛擬內存,虛擬內存由操作系統映射到物理內存。對于進程來說它就不需要關系實際的物理地址,當訪問到沒有映射的物理內存時,操作系統會捕捉到這個微法操作。同時進程是使用的虛擬內存,因為程序也具有移植性但是啊進程就算是操作虛擬內存但是最后也是映射到物理內存,如果給進程映射的物理內存不夠的時候,那還是得遷移。換出到磁盤進行遷移,粒度是整個進程,這么大的io肯定很漫長。想想一個程序中的數據,在不斷的運行使用的只有那么一部分,于是把常用的放在內存,不常用的放在磁盤中。那么換入換出的就是那么一少部分數據。然后這里就創建了更細的粒度–分頁機制想想為什么你的電腦內存條才8個G卻能跑幾十G的游戲。
2、解決辦法 level2 - 分頁機制
現在我們知道分頁粒度很細。進程的虛擬地址、硬件的物理地址都按照分頁的粒度。常用的代碼和數據以頁留在內存,不常用的去磁盤,這樣就節省了物理內存(內存那么貴)進程的虛擬內存頁通過CPU的硬件單元映射到物理內存頁物理頁稱為物理頁面或者頁幀進程空間的虛擬頁面稱為虛擬頁操作系統為了管控這些物理頁面,給頁幀創建了編號頁幀號 PFN現在的頁表常見的4KB最常見,還有16K、64K。在某些特點的場景下,比如那種超大服務器系統TB量級,可能頁面是M或者G級別。
到這里就說說那個CPU的硬件單元
其實雖然什么不想做的事情都扔給操作系統,但是做人不能這么狗,尤其是內存管理這么嚴重的事情,還有就是安全性(我這樣認為),于是用過CPU的硬件單元–MMU來管控這個內存的映射。
ARM處理器的內存管理單元包括TLB和Table Walk Unit兩個部件。
TLB是一塊高速緩存,用于緩存頁表轉換的結果,從而減少內存訪問的時間。就拿緩存的概念去理解。當TLB 沒有,miss了。那我就只能去內存的轉換頁表中獲取這個映射的結果,獲取到對應的物理地址后再將我的虛擬地址換成物理地址去最終的目的地查看學習資料。(有沒有中玩游戲闖關的感覺)
當然不是說有個這個玩意就什么不用做了。
一個完整的頁表翻譯和查找的過程叫作頁表查詢(Translation Table Walk),頁表查詢的過程由硬件自動完成,但是頁表的維護需要軟件來完成。
頁表查詢是一個相對耗時的過程,理想的狀態是TLB里緩存有頁表轉換的相關信息。當TLB未命中時,才會去查詢頁表,并且開始讀入頁表的內容。(要是這個TLB整大點,不是可以加快,不考慮錢的話)
因此頁表的維護是軟件的,所以在Linux內核內存的學習中,后面會有內存初始化,創建頁表這些東西。
3、虛擬內存到物理地址的轉換
上面那個圖里面,如果是TLBs命中后就直接拿到了物理地址,去兌換獎品,但是miss掉以后,那就得走Table Walk Uint就是得頁表轉換,VA–>PA(V:虛擬 P:物理 A:地址)
整個流程瞅瞅?
處理器根據頁表基地址控制寄存器TTBCR和虛擬地址來判斷使用哪個頁表基地址寄存器,是TTBR0還是TTBR1。(一個基值是內核的,一個用戶態的)
頁表基地址寄存器中存放著一級頁表的基地址。
處理器根據虛擬地址的bit[31:20]作為索引值()4K頁表,在一級頁表中找到頁表項。一級頁表一共有4 096個頁表項。
第一級頁表的表項中存放有二級頁表的物理基地址。處理器將虛擬地址的 bit[19:12]作為索引值,在二級頁表中找到相應的頁表項。二級頁表有256個頁表項(2^12 * 2^8 * 4kb(2^12)==》32位)。
二級頁表的頁表項里存放有 4KB 頁的物理基地址,加上最后的VA 12位,因此處理器就完成了頁表的查詢和翻譯工作。
(將整個4MB分成了4096份* 256份*4KB)
(這就是為什么內存越大,頁表項也得越大,不然頁表項的內存就變大的)
(表項存的是基地址,而虛擬內存放的都是索引)
圖 7.4 所示為 4KB 映射的一級頁表的表項,bit[1:0]表示一個頁映射的表項,bit[31:10]指向二級頁表的物理基地址。
4KB是2^12
64位的ARM 一般常用的是48,那么只剩36位(其他的位干啥了呢,記住這個問題哈哈哈)
這里還是討論32位
下圖展示兩個進程以及各自的頁表和物理內存的對應關系圖,這里假定頁大小是4K,32位地址總線進程地址空間大小為(2^32)4G,這時候頁表項有 4G / 4K = 1048576個,每個頁表項為一個地址,占用4字節,1048576 * 4(B) /1024(M) = 4M,也就是說一個程序啥都不干,頁表大小就得占用4M。如果每個頁表項都存在對應的映射地址那也就算了,但是,絕大部分程序僅僅使用了幾個頁,也就是說,只需要幾個頁的映射就可以了,如下圖,進程1的頁表,只用到了0,1,1024三個頁,剩下的1048573頁表項是空的,這就造成了巨大的浪費,為了避免內存浪費,計算機系統開發人員想出了一個方案,多級頁表。
我們先看下圖,這是一個兩級頁表,對應上圖中的進程1。先計算下兩級頁表的內存占用情況。
一級頁表占用= 1024 * 4 B= 4K,
2級頁表占用 = (1024 * 4 B) * 2 = 8K。
總共的占用情況是 12K,相比一級頁表 4M,節省了99.7%的內存占用。
我們來看下兩級頁表為啥能夠節省這么大的內存空間,相比于上圖單級頁表中一對一的關系,兩級頁表中的一級頁表項是一對多的關系,這里是1:1024, 這樣就需要 1048576 / 1024 = 1024 個一級頁表項。相當于把上圖的單級頁表分成1024份。一級頁表項PTE0表示虛擬地址頁01023,PTE1表示虛擬地址頁10242047。如果對應的1024個虛擬地址頁存在任意一個真實的映射,則一級頁表項指向一個二級頁表項,二級頁表項和虛擬地址頁一一對應,在上圖中,進程1的虛擬頁0,1,1024存在映射,0,1虛擬頁屬于這里的PTE0,1024屬于PTE1。一級頁表項中如果為null,表示對應的1024個虛擬頁沒有使用,所以就不需要二級頁表了,節省了空間。當然,如果虛擬地址頁完全映射的話,多級頁表的占用=一級頁表項(1024 * 4B) + 二級頁表項(1024 1024 4B) = 4M + 4K,比單級映射多了4K,不過這種情況基本上沒有可能,因為進程的地址空間很少有完全映射的情況。正是因為省卻了大量未映射的頁表項使得頁表的空間大幅減少。
其實這個差異就是我以前一來就把全部的虛擬頁表和物理頁表建立了映射關系,那我這個頁表就需要4M。
現在我將這個4M的頁表分成了1024份,需要幾份就申請創建幾份頁表,而不是一來就把所有的頁表都和物理頁面掛上鉤。
然后分成了這1024個,我需要在抽象一層4kb的頁表去指向這1024個頁表各自的基地址。
因為從物理內存層面一層一層的提到最上層的時候,也方便我們對于這個虛擬地址的組成:
一級頁表索引+二級頁表索引+VA(每次頁表的內容都是下一基的基地址)
(這個圖片稍微有點理想,一般都是4096 + 256的組合,而不是1014 + 1024的組合,不過大概這個道理就行)
那幾個特殊的位是內存的屬性。這個后面再補充。這個是ARM硬件架構上針對安全內存、設備內存的一些位。
審核編輯:湯梓紅
-
Linux
+關注
關注
87文章
11345瀏覽量
210387 -
操作系統
+關注
關注
37文章
6892瀏覽量
123742 -
程序
+關注
關注
117文章
3795瀏覽量
81406 -
內存管理
+關注
關注
0文章
168瀏覽量
14188
原文標題:Linux內存管理宏觀篇(一):不同角度去看內存(硬件)
文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論