自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

我的內(nèi)存怎么不夠用了?

存儲(chǔ) 存儲(chǔ)軟件
內(nèi)存是稀缺的,隨著應(yīng)用使用內(nèi)存也在膨脹。當(dāng)程序越來(lái)復(fù)雜,進(jìn)程對(duì)內(nèi)存的需求會(huì)越來(lái)越大。從安全角度考慮,進(jìn)程間使用內(nèi)存需要隔離。另外還有一些特殊場(chǎng)景,存在不希望 CPU 進(jìn)行緩存的場(chǎng)景。
本文轉(zhuǎn)載自微信公眾號(hào)「JerryCodes」,作者KyleJerry。轉(zhuǎn)載本文請(qǐng)聯(lián)系JerryCodes公眾號(hào)。  
  •  為什么內(nèi)存不夠用?
  • 交換(Swap)技術(shù)
  • 虛擬內(nèi)存
  • 頁(yè)(Page)和頁(yè)表
  • MMU
  • 頁(yè)表?xiàng)l目
  • 大頁(yè)面問(wèn)題

內(nèi)存是稀缺的,隨著應(yīng)用使用內(nèi)存也在膨脹。當(dāng)程序越來(lái)復(fù)雜,進(jìn)程對(duì)內(nèi)存的需求會(huì)越來(lái)越大。從安全角度考慮,進(jìn)程間使用內(nèi)存需要隔離。另外還有一些特殊場(chǎng)景,存在不希望 CPU 進(jìn)行緩存的場(chǎng)景。這個(gè)時(shí)候,有一個(gè)虛擬化層承接各種各樣的訴求,統(tǒng)一進(jìn)行處理,就會(huì)有很大的優(yōu)勢(shì)。

為什么內(nèi)存不夠用?

要理解一個(gè)技術(shù),就必須理解它為何而存在。總體來(lái)說(shuō),虛擬化技術(shù)是為了解決內(nèi)存不夠用的問(wèn)題,那么內(nèi)存為何不夠用呢?

主要是因?yàn)槌绦蛟絹?lái)越復(fù)雜。比如說(shuō)我現(xiàn)在給你錄音的機(jī)器上就有 200 個(gè)進(jìn)程,目前內(nèi)存的消耗是 21G,我的內(nèi)存是 64G 的,但是多開(kāi)一些程序還是會(huì)被占滿。另外,如果一個(gè)程序需要使用大的內(nèi)存,比如 1T,是不是應(yīng)該報(bào)錯(cuò)?如果報(bào)錯(cuò),那么程序就會(huì)不好寫(xiě),程序員必須小心翼翼地處理內(nèi)存的使用,避免超過(guò)允許的內(nèi)存使用閾值。以上提到的這些都是需要解決的問(wèn)題,也是虛擬化技術(shù)存在的價(jià)值和意義。

那么如何來(lái)解決這些問(wèn)題呢?歷史上有過(guò)不少的解決方案,但最終沉淀下的是虛擬化技術(shù)。接下來(lái)我為你介紹一種歷史上存在過(guò)的 Swap 技術(shù)以及虛擬化技術(shù)。

交換(Swap)技術(shù)

Swap 技術(shù)允許一部分進(jìn)程使用內(nèi)存,不使用內(nèi)存的進(jìn)程數(shù)據(jù)先保存在磁盤(pán)上。注意,這里提到的數(shù)據(jù),是完整的進(jìn)程數(shù)據(jù),包括正文段(程序指令)、數(shù)據(jù)段、堆棧段等。輪到某個(gè)進(jìn)程執(zhí)行的時(shí)候,嘗試為這個(gè)進(jìn)程在內(nèi)存中找到一塊空閑的區(qū)域。如果空間不足,就考慮把沒(méi)有在執(zhí)行的進(jìn)程交換(Swap)到磁盤(pán)上,把空間騰挪出來(lái)給需要的進(jìn)程。

 

上圖中,內(nèi)存被拆分成多個(gè)區(qū)域。內(nèi)核作為一個(gè)程序也需要自己的內(nèi)存。另外每個(gè)進(jìn)程獨(dú)立得到一個(gè)空間——我們稱為地址空間(Address Space)。你可以認(rèn)為地址空間是一塊連續(xù)分配的內(nèi)存塊。每個(gè)進(jìn)程在不同地址空間中工作,構(gòu)成了一個(gè)原始的虛擬化技術(shù)。

比如:當(dāng)進(jìn)程 A 想訪問(wèn)地址 100 的時(shí)候,實(shí)際上訪問(wèn)的地址是基于地址空間本身位置(首字節(jié)地址)計(jì)算出來(lái)的。另外,當(dāng)進(jìn)程 A 執(zhí)行時(shí),CPU 中會(huì)保存它地址空間的開(kāi)始位置和結(jié)束位置,當(dāng)它想訪問(wèn)超過(guò)地址空間容量的地址時(shí),CPU 會(huì)檢查然后報(bào)錯(cuò)。

上圖描述的這種方法,是一種比較原始的虛擬化技術(shù),進(jìn)程使用的是基于地址空間的虛擬地址。但是這種方案有很多明顯的缺陷,比如:

  1. 碎片問(wèn)題:上圖中我們看到進(jìn)程來(lái)回分配、回收交換,內(nèi)存之間會(huì)產(chǎn)生很多縫隙。經(jīng)過(guò)反反復(fù)復(fù)使用,內(nèi)存的情況會(huì)變得十分復(fù)雜,導(dǎo)致整體性能下降。
  2. 頻繁切換問(wèn)題:如果進(jìn)程過(guò)多,內(nèi)存較小,會(huì)頻繁觸發(fā)交換。

首先重新 Review 下我們的設(shè)計(jì)目標(biāo)。

  1. 隔離:每個(gè)應(yīng)用有自己的地址空間,互不影響。
  2. 性能:高頻使用的數(shù)據(jù)保留在內(nèi)存中、低頻使用的數(shù)據(jù)持久化到磁盤(pán)上。
  3. 程序好寫(xiě)(降低程序員心智負(fù)擔(dān)):讓程序員不用關(guān)心底層設(shè)施。

現(xiàn)階段,Swap 技術(shù)已經(jīng)初步解決了問(wèn)題 1。

關(guān)于問(wèn)題 2,Swap 技術(shù)在性能上存在著碎片、頻繁切換等明顯劣勢(shì)。

關(guān)于問(wèn)題3, 使用 Swap 技術(shù),程序員需要清楚地知道自己的應(yīng)用用多少內(nèi)存,并且小心翼翼地使用內(nèi)存,避免需要重新申請(qǐng),或者研發(fā)不斷擴(kuò)容的算法——這讓程序心智負(fù)擔(dān)較大。

經(jīng)過(guò)以上分析,需要更好的解決方案,就是我們接下來(lái)要學(xué)習(xí)的虛擬化技術(shù)。

虛擬內(nèi)存

虛擬化技術(shù)中,操作系統(tǒng)設(shè)計(jì)了虛擬內(nèi)存(理論上可以無(wú)限大的空間),受限于 CPU 的處理能力,通常 64bit CPU,就是 264 個(gè)地址。

 

虛擬化技術(shù)中,應(yīng)用使用的是虛擬內(nèi)存,操作系統(tǒng)管理虛擬內(nèi)存和真實(shí)內(nèi)存之間的映射。操作系統(tǒng)將虛擬內(nèi)存分成整齊小塊,每個(gè)小塊稱為一個(gè)頁(yè)(Page)。之所以這樣做,原因主要有以下兩個(gè)方面。

一方面應(yīng)用使用內(nèi)存是以頁(yè)為單位,整齊的頁(yè)能夠避免內(nèi)存碎片問(wèn)題。

另一方面,每個(gè)應(yīng)用都有高頻使用的數(shù)據(jù)和低頻使用的數(shù)據(jù)。這樣做,操作系統(tǒng)就不必從應(yīng)用角度去思考哪個(gè)進(jìn)程是高頻的,僅需思考哪些頁(yè)被高頻使用、哪些頁(yè)被低頻使用。如果是低頻使用,就將它們保存到硬盤(pán)上;如果是高頻使用,就讓它們保留在真實(shí)內(nèi)存中。

如果一個(gè)應(yīng)用需要非常大的內(nèi)存,應(yīng)用申請(qǐng)的是虛擬內(nèi)存中的很多個(gè)頁(yè),真實(shí)內(nèi)存不一定需要夠用。

頁(yè)(Page)和頁(yè)表

接下來(lái),我們?cè)敿?xì)討論下這個(gè)設(shè)計(jì)。操作系統(tǒng)將虛擬內(nèi)存分塊,每個(gè)小塊稱為一個(gè)頁(yè)(Page);真實(shí)內(nèi)存也需要分塊,每個(gè)小塊我們稱為一個(gè) Frame。Page 到 Frame 的映射,需要一種叫作頁(yè)表的結(jié)構(gòu)。

上圖展示了 Page、Frame 和頁(yè)表 (PageTable)三者之間的關(guān)系。Page 大小和 Frame 大小通常相等,頁(yè)表中記錄的某個(gè) Page 對(duì)應(yīng)的 Frame 編號(hào)。頁(yè)表也需要存儲(chǔ)空間,比如虛擬內(nèi)存大小為 10G, Page 大小是 4K,那么需要 10G/4K = 2621440 個(gè)條目。如果每個(gè)條目是 64bit,那么一共需要 20480K = 20M 頁(yè)表。操作系統(tǒng)在內(nèi)存中劃分出小塊區(qū)域給頁(yè)表,并負(fù)責(zé)維護(hù)頁(yè)表。

 

頁(yè)表維護(hù)了虛擬地址到真實(shí)地址的映射。每次程序使用內(nèi)存時(shí),需要把虛擬內(nèi)存地址換算成物理內(nèi)存地址,換算過(guò)程分為以下 3 個(gè)步驟:

  1. 通過(guò)虛擬地址計(jì)算 Page 編號(hào);
  2. 查頁(yè)表,根據(jù) Page 編號(hào),找到 Frame 編號(hào);
  3. 將虛擬地址換算成物理地址。

下面我通過(guò)一個(gè)例子給你講解上面這個(gè)換算的過(guò)程:如果頁(yè)大小是 4K,假設(shè)程序要訪問(wèn)地址:100,000。那么計(jì)算過(guò)程如下。

頁(yè)編號(hào)(Page Number) = 100,000/4096 = 24 余1619。24 是頁(yè)編號(hào),1619 是地址偏移量(Offset)。

查詢頁(yè)表,得到 24 關(guān)聯(lián)的 Frame 編號(hào)(假設(shè)查到 Frame 編號(hào) = 10)。

換算:通常 Frame 和 Page 大小相等,替換 Page Number 為 Frame Number 物理地址 = 4096 * 10 + 1619 = 42579。

MMU

上面的過(guò)程發(fā)生在 CPU 中一個(gè)小型的設(shè)備——內(nèi)存管理單元(Memory Management Unit, MMU)中。如下圖所示:

 

當(dāng) CPU 需要執(zhí)行一條指令時(shí),如果指令中涉及內(nèi)存讀寫(xiě)操作,CPU 會(huì)把虛擬地址給 MMU,MMU 自動(dòng)完成虛擬地址到真實(shí)地址的計(jì)算;然后,MMU 連接了地址總線,幫助 CPU 操作真實(shí)地址。

這樣的設(shè)計(jì),就不需要在編寫(xiě)應(yīng)用程序的時(shí)候擔(dān)心虛擬地址到物理地址映射的問(wèn)題。我們把全部難題都丟給了操作系統(tǒng)——操作系統(tǒng)要確定MMU 可以讀懂自己的頁(yè)表格式。所以,操作系統(tǒng)的設(shè)計(jì)者要看 MMU 的說(shuō)明書(shū)完成工作。

難點(diǎn)在于不同 CPU 的 MMU 可能是不同的,因此這里會(huì)遇到很多跨平臺(tái)的問(wèn)題。解決跨平臺(tái)問(wèn)題不但有繁重的工作量,更需要高超的編程技巧,Unix 最初期的移植性(跨平臺(tái))是 C 語(yǔ)言作者丹尼斯·里奇實(shí)現(xiàn)的。

MMU 需要查詢頁(yè)表(這是內(nèi)存操作),而 CPU 執(zhí)行一條指令通過(guò) MMU 獲取內(nèi)存數(shù)據(jù),難道可以容忍在執(zhí)行一條指令的過(guò)程中,發(fā)生多次內(nèi)存讀取(查詢)操作?難道一次普通的讀取操作,還要附加幾次查詢頁(yè)表的開(kāi)銷嗎?當(dāng)然不是,這里還有一些高速緩存的設(shè)計(jì),這部分后面還可以繼續(xù)討論。

頁(yè)表?xiàng)l目

上面我們籠統(tǒng)介紹了頁(yè)表將 Page 映射到 Frame。那么,頁(yè)表中的每一項(xiàng)(頁(yè)表?xiàng)l目)長(zhǎng)什么樣子呢?下圖是一個(gè)頁(yè)表格式的一個(gè)演示。

 

頁(yè)表?xiàng)l目本身的編號(hào)可以不存在頁(yè)表中,而是通過(guò)偏移量計(jì)算。比如地址 100,000 的編號(hào),可以用 100,000 除以頁(yè)大小確定。

  • Absent(“在”)位,是一個(gè) bit。0 表示頁(yè)的數(shù)據(jù)在磁盤(pán)中(不再內(nèi)存中),1 表示在內(nèi)存中。如果讀取頁(yè)表發(fā)現(xiàn) Absent = 0,那么會(huì)觸發(fā)缺頁(yè)中斷,去磁盤(pán)讀取數(shù)據(jù)。
  • Protection(保護(hù))字段可以實(shí)現(xiàn)成 3 個(gè) bit,它決定頁(yè)表用于讀、寫(xiě)、執(zhí)行。比如 000 代表什么都不能做,100 代表只讀等。
  • Reference(訪問(wèn))位,代表這個(gè)頁(yè)被讀寫(xiě)過(guò),這個(gè)記錄對(duì)回收內(nèi)存有幫助。
  • Dirty(“臟”)位,代表頁(yè)的內(nèi)容被修改過(guò),如果 Dirty =1,那么意味著頁(yè)面必須回寫(xiě)到磁盤(pán)上才能置換(Swap)。如果 Dirty = 0,如果需要回收這個(gè)頁(yè),可以考慮直接丟棄它(什么也不做,其他程序可以直接覆蓋)。
  • Caching(緩存位),描述頁(yè)可不可以被 CPU 緩存。CPU 緩存會(huì)造成內(nèi)存不一致問(wèn)題,在上個(gè)模塊的加餐中我們討論了內(nèi)存一致性問(wèn)題,具體你可以參考“模塊四”的加餐內(nèi)容。

Frame Number(Frame 編號(hào)),這個(gè)是真實(shí)內(nèi)存的位置。用 Frame 編號(hào)乘以頁(yè)大小,就可以得到 Frame 的基地址。

在 64bit 的系統(tǒng)中,考慮到 Absent、Protection 等字段需要占用一定的位,因此不能將 64bit 都用來(lái)描述真實(shí)地址。但是 64bit 可以尋址的空間已經(jīng)遠(yuǎn)遠(yuǎn)超過(guò)了 EB 的級(jí)別(1EB = 220TB),這已經(jīng)足夠了。在真實(shí)世界,我們還造不出這么大的內(nèi)存呢。

大頁(yè)面問(wèn)題

最后,我們討論一下大頁(yè)面的問(wèn)題。假設(shè)有一個(gè)應(yīng)用,初始化后需要 12M 內(nèi)存,操作系統(tǒng)頁(yè)大小是 4K。那么應(yīng)該如何設(shè)計(jì)呢?

為了簡(jiǎn)化模型,下圖中,假設(shè)這個(gè)應(yīng)用只有 3 個(gè)區(qū)域(3 個(gè)段)——正文段(程序)、數(shù)據(jù)段(常量、全局變量)、堆棧段。一開(kāi)始我們 3 個(gè)段都分配了 4M 的空間。隨著程序執(zhí)行,堆棧段的空間會(huì)繼續(xù)增加,上不封頂。

上圖中,進(jìn)程內(nèi)部需要一個(gè)頁(yè)表存儲(chǔ)進(jìn)程的數(shù)據(jù)。如果進(jìn)程的內(nèi)存上不封頂,那么頁(yè)表有多少個(gè)條目合適呢?進(jìn)程分配多少空間合適呢?如果頁(yè)表大小為 1024 個(gè)條目,那么可以支持 1024*4K = 4M 空間。按照這個(gè)計(jì)算,如果進(jìn)程需要 1G 空間,則需要 256K 個(gè)條目。我們預(yù)先為進(jìn)程分配這 256K 個(gè)條目嗎?創(chuàng)建一個(gè)進(jìn)程就劃分這么多條目是不是成本太高了?

 

為了減少條目的創(chuàng)建,可以考慮進(jìn)程內(nèi)部用一個(gè)更大的頁(yè)表(比如 4M),操作系統(tǒng)繼續(xù)用 4K 的頁(yè)表。這就形成了一個(gè)二級(jí)頁(yè)表的結(jié)構(gòu),如下圖所示:

 

這樣 MMU 會(huì)先查詢 1 級(jí)頁(yè)表,再查詢 2 級(jí)頁(yè)表。在這個(gè)模型下,進(jìn)程如果需要 1G 空間,也只需要 1024 個(gè)條目。比如 1 級(jí)頁(yè)編號(hào)是 2, 那么對(duì)應(yīng) 2 級(jí)頁(yè)表中 [2* 1024, 3*1024-1] 的部分條目。而訪問(wèn)一個(gè)地址,需要同時(shí)給出一級(jí)頁(yè)編號(hào)和二級(jí)頁(yè)編號(hào)。整個(gè)地址,還可以用 64bit 組裝,如下圖所示:

MMU 根據(jù) 1 級(jí)編號(hào)找到 1 級(jí)頁(yè)表?xiàng)l目,1 級(jí)頁(yè)表?xiàng)l目中記錄了對(duì)應(yīng) 2 級(jí)頁(yè)表的位置。然后 MMU 再查詢 2 級(jí)頁(yè)表,找到 Frame。最后通過(guò)地址偏移量和 Frame 編號(hào)計(jì)算最終的物理地址。這種設(shè)計(jì)是一個(gè)遞歸的過(guò)程,因此還可增加 3 級(jí)、4 級(jí)……每增加 1 級(jí),對(duì)空間的利用都會(huì)提高——當(dāng)然也會(huì)帶來(lái)一定的開(kāi)銷。這對(duì)于大應(yīng)用非常劃算,比如需要 1T 空間,那么使用 2 級(jí)頁(yè)表,頁(yè)表的空間就節(jié)省得多了。而且,這種多級(jí)頁(yè)表,頂級(jí)頁(yè)表在進(jìn)程中可以先只創(chuàng)建需要用到的部分,就這個(gè)例子而言,一開(kāi)始只需要 3 個(gè)條目,從 256K 個(gè)條目到 3 個(gè),這就大大減少了進(jìn)程創(chuàng)建的成本。

 

責(zé)任編輯:武曉燕 來(lái)源: JerryCodes
相關(guān)推薦

2013-12-19 10:08:52

AWS服務(wù)器

2024-11-22 12:32:34

TypeScript校驗(yàn)靜態(tài)類型

2024-07-25 12:33:45

2019-07-24 14:05:17

Redis內(nèi)存集群

2019-07-25 15:23:05

Redis電腦數(shù)據(jù)庫(kù)

2013-06-14 13:27:36

內(nèi)存Linux交換分區(qū)

2015-07-16 15:16:41

內(nèi)存泄露解決辦法

2019-11-15 10:41:10

Vim分屏終端

2022-08-01 10:00:47

AI趨勢(shì)

2017-03-23 11:24:26

Windows 10Windows系統(tǒng)盤(pán)

2023-06-12 07:20:39

2023-05-17 07:28:18

電腦16GB內(nèi)存

2013-05-02 09:16:16

程序員

2024-08-05 11:08:53

內(nèi)存File項(xiàng)目

2016-11-25 15:03:33

FacebookWIFI

2013-10-23 14:28:30

2018-11-22 14:34:01

局域網(wǎng)IP擴(kuò)容

2021-08-08 08:17:45

事件響應(yīng)日志網(wǎng)絡(luò)安全

2022-02-01 15:38:04

手機(jī)內(nèi)存數(shù)據(jù)備份
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)