對于人類來說,我們不喜歡拐彎抹角,喜歡更直接的東西,“有話直說”、“沒有中間商賺差價(jià)”、“簡潔的設(shè)計(jì)”等等,然而對于計(jì)算機(jī),尤其是對內(nèi)存管理來說則恰恰相反, 在這里"簡潔"的設(shè)計(jì)往往不是好的設(shè)計(jì) ,這到底是什么意思呢?
我們在很早的文章中就提到過,內(nèi)存從本質(zhì)上將非常簡單,你可以將其想像成一個個的小盒子組成,每個小盒子要么能存儲1要么存儲0,每8個小盒子組成一個字節(jié)(8比特),每個字節(jié)都有一個唯一的地址,通過這個地址我們就能從相應(yīng)的一組小盒子取出這個比特。
其它沒了。
看到了吧,內(nèi)存本身其實(shí)是非常簡單的,然而程序員以及程序使用內(nèi)存的方式又讓這個問題變得復(fù)雜起來,分析任何復(fù)雜問題都要抓住重點(diǎn)、抓住核心問題,那么這里的重點(diǎn)以及核心是什么呢?
不賣關(guān)子,這里的核心在于兩個字: 尋址 ,Addressing。
一切都是圍繞尋址展開的。
尋址,最重要的就是尋址
什么是尋址 Addressing?所謂尋址就是找到內(nèi)存中某個我們需要的數(shù)據(jù)的方式。
哪怕以我們平時去儲物柜取東西都有很多“尋址”方式:
-
直接告訴我們一個編號,我們拿到這個編號后按個去找,就像下面這張圖,我們需要找到東西在第15號儲物柜中,那么我們根據(jù)15這個地址就能找到第15號儲物柜。
-
當(dāng)然我們也可以將儲物柜劃分區(qū)域,還是以剛才的儲物柜為例我們可以劃分為3個區(qū)域,當(dāng)我們需要找東西時告訴我們其在儲物柜的哪個區(qū)域,以及在該區(qū)域中的"偏移"是多少。
以下圖為例我們需要的東西在第二個區(qū)域,區(qū)域內(nèi)的偏移為6(該區(qū)域中的第6個儲物柜)。
實(shí)際上,第一種更像是“絕對尋址”,什么意思呢?就是找到某個具體的儲物柜是根據(jù)一個“寫死的地址”(hardcode),很死板,第二種更像是相對尋址,稍顯靈活一些。
怎么樣,你是不是感覺這兩種其實(shí)也沒什么區(qū)別嘛,的確,對于找儲物柜這個例子來說這兩種方式的確沒什么區(qū)別,但對于內(nèi)存來說就不太一樣了。
死板 vs 靈活
我們知道程序以及程序使用的數(shù)據(jù)編譯好后存放在磁盤上,運(yùn)行時要加載到內(nèi)存中,因此這里同樣存在尋址問題:我們需要根據(jù)內(nèi)存地址找到機(jī)器指令以及數(shù)據(jù),接下來假設(shè)有一個只有8字節(jié)大小的內(nèi)存和一個只有2字節(jié)機(jī)器指令的程序(無需關(guān)心實(shí)際意義):
這段2字節(jié)的代碼非常簡單,其實(shí)就是一個無意義的while循環(huán),注意看這里的jmp這條指令,我們直接跳轉(zhuǎn)到內(nèi)存地址2,這就是一個寫死(hard code)的內(nèi)存地址,這就意味著我們必須把該程序加載到內(nèi)存地址為2的位置上:
否則這段指令根本沒有辦法運(yùn)行,比如我們把這段代碼加載到內(nèi)存地址6上去:
那么在執(zhí)行jmp 2時我們根本沒有辦法跳轉(zhuǎn)到add這行指令,有的同學(xué)可能覺得無所謂,不就是內(nèi)存地址寫死了嘛,好像也沒什么大不了的吧。
如果一次只能運(yùn)行一個程序的確也沒什么大不了的,但對于操作系統(tǒng)最核心的功能之一:多任務(wù),也就是一次可以運(yùn)行多個程序來說這個方案簡直行不通。
在這種方案下你幾乎沒有辦法一次運(yùn)行多個程序,除非在運(yùn)行之前你給要運(yùn)行的這幾個程序劃定好區(qū)域,比如要運(yùn)行兩個程序A和B,A占用03這個區(qū)域的內(nèi)存;B占用46這個區(qū)域的內(nèi)存, 對于現(xiàn)代程序員來說你能想象在程序運(yùn)行之前就需要給它劃定好區(qū)域嗎? 顯然,這非常繁瑣,也容易出錯。
如果你在上世紀(jì)六七十年代寫代碼,面臨的大概就是這樣一種狀況。
實(shí)際上這個問題的核心就在于 重定位 , 程序使用的地址不能綁定在一個內(nèi)存區(qū)域上,需要足夠靈活,我們需要在不修改代碼的情況下把程序加載到任意內(nèi)存區(qū)域上運(yùn)行! 想一想該怎么解決這個問題。
作為程序員肯定和文件路徑打過交道,如果你能明白絕對路徑與相對路徑就能解決重定位問題。
絕對路徑與相對路徑
想一想絕對地址有什么問題?這個問題就好比你在程序中讀取一個絕對地址時:
/user/xiaofeng/doc/a.c
如果是你自己的計(jì)算機(jī)那么沒有問題, 但如果這個程序在其它人的計(jì)算機(jī)上運(yùn)行就不一定了,因?yàn)槠渌说挠?jì)算機(jī)中不一定有這個路徑 ,這時該怎么辦呢?聰明的你一定知道,那就不要使用絕對路徑,而是使用相對路徑就可了:
./a.c
其中./表示程序運(yùn)行時所在的路徑,這時不管這個程序在哪個路徑下運(yùn)行都能找到a.c這個文件,這時所在的目錄就成為了 基準(zhǔn) 。
解決重定位這個問題也是同樣的道理,編程生成可執(zhí)行程序時不再使用 絕對內(nèi)存地址 ,而是使用相對地址,怎么使用相對地址呢?相對于誰呢?很簡單, 相對于該程序被加載到的內(nèi)存起始地址 。
此時我們的jmp命令后面不再是一個絕對的內(nèi)存地址,而是一個相對地址:0,但畢竟向內(nèi)存發(fā)出讀寫指令時必須使用一個內(nèi)存地址,那么CPU執(zhí)行jmp 0時該怎樣將其轉(zhuǎn)為一個內(nèi)存地址呢?
很簡單,因?yàn)檫@一段程序被加載到了內(nèi)存起始地址2,因此只需要用相對地址加上起始地址得到的就是真實(shí)的物理內(nèi)存地址:
物理地址 = 起始地址 + 相對地址
很簡單吧, 這樣不管這段程序被加載到了哪個內(nèi)存區(qū)域,只要我們知道起始地址那么總能計(jì)算出真實(shí)的物理內(nèi)存地址 ,重定位問題就可以這樣解決。
實(shí)際上你會發(fā)現(xiàn), 這個儲物柜的第二種尋址方式也沒有什么區(qū)別 。
-
cpu
+關(guān)注
關(guān)注
68文章
11055瀏覽量
216320 -
內(nèi)存
+關(guān)注
關(guān)注
8文章
3115瀏覽量
75074 -
操作系統(tǒng)
+關(guān)注
關(guān)注
37文章
7114瀏覽量
125155
發(fā)布評論請先 登錄
什么是操作系統(tǒng)
【安富萊】【RTX操作系統(tǒng)教程】第21章 RTX低功耗之睡眠模式
ARM CPU操作系統(tǒng)
HarmonyOS鴻蒙操作系統(tǒng)之什么是“基于微內(nèi)核的全場景分布式操作系統(tǒng)”?
如何選擇ARM CPU的操作系統(tǒng)?
MOS微型操作系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)
什么是VxWorks操作系統(tǒng)
32位cpu、程序、操作系統(tǒng)是什么意思
ARM CPU的操作系統(tǒng)選擇要點(diǎn)
Linux操作系統(tǒng)實(shí)訓(xùn)項(xiàng)目_虛擬機(jī)設(shè)置基礎(chǔ)_RHEL_5.0_2
EMWIN實(shí)驗(yàn)之STemWin無操作系統(tǒng)移植-T

Linux操作系統(tǒng)上的射頻測試模式應(yīng)用指南

國產(chǎn)CPU和操作系統(tǒng)被納入政府采購清單:加速換國產(chǎn)OS

評論