虛擬內存與mmap,brk

虛擬內存與mmap,brk

  1. 基本概念及相關術語

1.1 基本概念

虛擬內存使得應用程序認為它擁有連續的可用的內存(一個連續完整的地址空間),而實際上,它通常是被分隔成多個物理內存碎片,還有部分暫時存儲在外部磁盤存儲器上,在需要時進行數據交換。即將不完整,不連續的物理內存映射為連續的虛擬內存。虛擬內存主要有以下三個作用:

(1) 它將主存看成是磁盤的一個高速緩存,只在主存中保存活動區域(通常一個進程只有執行上下文被加載到主存,其余的在磁盤中,隨用隨加載);

(2) 為每個進程提供一致的地址空間,簡化了內存管理;

(3) 它保護每個進程的地址空間不被其他進程破壞(在頁表的PTE條目中加入額外控制信息實現內存保護)。

虛擬內存有兩個重要的地址,虛擬地址(virtual address, VA)和物理地址(physical address)。在訪問某個對象時,CPU給出虛擬地址,通過查詢計算得到物理地址,然后訪問物理地址上的對象。整個過程如下圖:

                                        圖1  CPU訪問主存

1.2 相關術語

在表述虛擬內存相關概念時,有些約定的縮寫和表達方式

N=2n:虛擬地址數量,n表示虛擬地址位數;
M=2m:物理地址數量,m表示物理地址位數;
P=2p:頁大小,p表示頁偏移量的位數;
VPO(virtual page offset):虛擬地址頁偏移;
VPN(virtual page number):虛擬地址頁號;
PPO(physical page offset):物理地址頁偏移;
PPN(physical page number):物理地址頁號。
頁表(Page Table, PT):記錄虛擬地址到物理地址的映射的表
頁表項(Page Table Entry, PTE):頁表中一行,PTE的索引即VPN;
頁表項地址(PTEA):在CPU中有個頁表基址寄存器,記錄頁表起始地址,頁表基址寄存器+PTE索引=PTEA;
MMU(Memory Management Unit):內存管理單元,用于虛擬地址到物理地址尋址的硬件。
一個頁表的常見結構如下圖:

                                  圖2 頁表常見結構(有效位表示該PTE是否有VP到PP的映射)

eg: 給定一個32位虛擬地址空間和一個24位物理地址空間,,對于下面的頁大小,確定VPN,VPO,PPN,PPO的位數。

P VPN位數 VPO位數 PPN位數 PPO位數
1KB 22 10 14
10

4KB 20 12 12
12

注:VPO表示對象在頁中的偏移,VPO=PPO,VPO位數=log2§,VPN表示虛擬頁號,對應PTE表索引,PPN表示物理頁號。

一個虛擬地址翻譯成物理地址,方法如下圖:

                        圖3 虛擬地址翻譯為物理地址

地址翻譯時,給定虛擬地址,低p位表示頁偏移,其中VPO=PPO,高n-p位表示虛擬頁號,即PTE的索引號,找到對應PTE記錄,得到物理頁號PPN,跟PPO組合得到物理地址。所以訪問一個對象,首先訪問頁表,從虛擬地址轉化為物理地址,再從訪問物理地址得到對象。由于頁表和物理地址都在內存中,因此存在兩次內存訪問。

1.3 地址翻譯加速

從1.2中得知為了訪問對象,需要兩次內存訪問,每次內存訪問一般幾十到幾百個周期,為了加快地址翻譯,減少內存訪問次數,有兩種輔助設備:SRAM緩存和TLB緩存。

SRAM緩存:在CPU和主存(DRAM)之間,還有L1, L2, L3三級高速緩存(SRAM)。因此,可以將部分PTE條目和對象存到SRAM中,減少內存訪問次數,添加了SRAM的訪問機制如下圖。

                                 圖4 加入SRAM的對象訪問過程

可見,在訪問時,優先訪問SRAM獲取PTE和數據,沒有再訪問主存,還沒有則引起缺頁中斷。SRAM的訪問通常幾個時間周期。

TLB緩存:在MMU中的虛擬地址緩存器,稱為翻譯后備寄存器(Translantion Lookaside Buffer)。每一行由一個或多個PTE條目組成,其中TLBI用于行號索引,TLBT用于同一行某個PTE的選擇。

                                                      圖5 虛擬地址在TLB中的含義

比如某一時刻,TLB中的快照如下:

                                                                     圖6 TLB快照,四組,四路組相聯 

頁面大小64字節,虛擬地址長度14位,物理地址長度為12位。給定虛擬地址0x03d4,其二進制表示為0b 00 0011 1101 0100,低6位0b 01 0100為VPO,因為四路組相聯,所以第6-7位為TLBI(TLB索引),為0b 11,剩余為TLBT(TLB標記),TLBI表示TLB表的行號,找到TLBT為0x03的位置,得到PPN為0D。結合VPO,得到物理地址為0b 0011 0101 0100,即0x0354。加入TLB之后的對象訪問過程如下:

                                                圖7 加入TLB的對象訪問過程
  1. Linux虛擬內存

2.1 Linux虛擬內存組織機制

Linux系統為每個進程維護一個單獨的地址空間,如圖8(a)所示,同時為每個進程維護一個結構體,其中包含虛擬內存相關信息,如圖8(b)所示。

(a) Linux進程的虛擬內存 (b)管理虛擬內存的結構體

                          圖8 Linux虛擬內存

其中vm_prot描述虛擬內存頁的讀寫權限,vm_flags記錄該虛擬頁是共享還是私有等其他常見信息。

2.2 內存映射

Linux系統將虛擬內存和一個磁盤對象關聯起來,以初始化虛擬內存區域的內容,稱為內存映射。有兩種類型的內存映射:

(1) 映射到Linux文件系統中的普通文件;

(2) 映射到匿名文件,匿名文件是由內核創建的全是二進制0的文件,CPU第一次使用該虛擬頁面時,內核就選擇一個物理頁面進行覆蓋(整個過程沒有跟磁盤發生數據交互)。

一個對象映射到虛擬內存中,要么以共享對象存在,要么以私有對象存在。不論哪一種模式,在物理內存中只有一份副本。共享對象一個進程的寫操作,其他進程都可見,并且能反映到磁盤上;私有對象一個進程的寫操作,其他進程不可見,并且不能反映到磁盤上。

        (a) 內存映射到共享區域                                                  (b) 內存映射到私有區域圖9 多個進程映射同一對象

對于多個進程內存映射到私有區域時,物理內存只有一份副本,此時采用一種"寫時復制"策略。即進程在寫時,復制修改的部分到內存其他區域。這樣對其他進程來說,對象沒有修改過。

2.3 mmap函數

mmap函數提供用戶級的內存映射,該函數能夠把某個磁盤文件映射到內存中,函數的主要格式如下:

復制代碼
void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
start:內存起始地址,通常為NULL,讓系統自己選擇
length:內存的長度
prot:
PROT_READ:數據可讀
PROT_WRITE:數據可寫
PROT_EXEC:數據可執行
PROT_NONE:數據不可訪問
flags:
MAP_SHARED:共享對象,進程間可察覺修改,并能反映到磁盤
MAP_PRIVATE:私有對象,一切操作只在本進程可見,修改不會寫入磁盤
MAP_FIXED:基本不用
fd:映射的文件的描述符,通常應先打開文件,再調用mmap,此后關閉文件映射仍然存在
offset:文件偏移量,一般為0
該函數返回內存中對應的地址
復制代碼
調用mmap之后,內存與磁盤文件之間就建立了映射關系,如下圖所示:

munmap用于解除映射關系

int munmap(void* start,size_t length);
使用mmap的作用主要有以下兩個:

(1) 將磁盤文件映射到內存中,這樣所有讀寫均針對內存讀寫(可以使用memcpy等內存操作函數,而不是read,write等IO操作函數),加快訪問速度;

(2) 在無親緣關系的進程間提供共享內存。

使用mmap函數,需要注意以下問題:

(1) 在文件映射之前,必須打開該文件,而且mmap的prot權限不能超過打開的權限。比如open打開時只設置了讀文件,那么prot就不能設置PROT_WRITE;

(2) 內存映射通常都是按虛擬內存的頁為基本單位的。比如一個頁512字節,但是映射的文件只有12字節。那么剩下的500字節會自動填充為零,即時修改了后面的500字節,也不會寫入到文件(所以較好的操作是直到文件大小,直接加長文件);

(3) 如果試圖訪問不存在的映射關系,比如頁面大小512字節,實際文件大小為12字節,用mmap映射的時候映射1000個字節,那么實際可操作的結果如下:

(4) 將內存寫入磁盤的操作通常由頁守護進程完成,如果想人為控制將內存數據寫入磁盤,可以調用以下函數:

復制代碼
#include <sys/mman.h>

int msync(void *addr,size_t len,int flags);

flags:
MS_ASYC:異步寫入
MS_SYC:同步寫入,等待寫入之后才會返回
復制代碼
(5) 進程終止或調用munmap時解除映射關系,關閉文件描述符不會解除映射關系。

下面舉一個簡單的例子:父子進程同時修改一個文件寫入數據:

復制代碼
1 #include <sys/mman.h>
2 #include <stdio.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <sys/wait.h>
6 #include <sys/types.h>
7 #include <stdlib.h>
8 #include <string.h>
9
10 #define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH)
11
12 int main()
13 {
14 int fd;
15 if((fd=open(“map.txt”,O_RDWR|O_CREAT|O_TRUNC,FILE_MODE))<0)
16 {
17 printf(“open file failed\n”);
18 exit(1);
19 }
20
21
22 if(ftruncate(fd,50)<0) //文件大小50字節
23 {
24 printf(“ftruncate error\n”);
25 exit(1);
26 }
27
28 char buf;//起始地址
29
30 buf=(char
)mmap(NULL,50,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
31 close(fd);
32 pid_t pid;
33 if((pid=fork())<0)
34 printf(“fork error\n”);
35
36 char* msg=“hello world\n”;
37 char* msg1= “good news”;
38 if(pid==0) //子進程
39 {
40 memcpy(buf,msg,strlen(msg));
41 exit(0);
42 }
43 else
44 {
45 int stat;
46 wait(&stat);
47 memcpy(buf+strlen(msg),msg1,strlen(msg1));
48 }
49 return 0;
50
51 }
復制代碼
第22-26行就是申請文件大小為50字節,那么實際內存可修改的部分就是buf~(buf+49)。注釋該段再執行就會報SIGBUS錯誤。

執行結果是當前目錄多了map.txt,其內容為:

hello world

good news

2.4 Linux進程分配內存的方式

關于此部分詳細介紹參考博文:https://www.cnblogs.com/vinozly/p/5489138.html

簡單來說,當我們調用分配內存的函數時(如malloc),底層通過調用brk()或mmap()實現。當遇到小于128KB的內存時,調用brk()函數將數據段堆的_edata地址往高地址推(即圖8a中brk指向的指針,此時只分配虛擬內存,沒有物理內存。當產生缺頁中斷時,才調用物理內存)。當申請內存大于128KB時,調用mmap()在堆棧之間的共享區域分配內存(此部分內存可以單獨釋放)。

標簽: 虛擬內存 , 計算機基礎 , 操作系統 , mmap
好文要頂 關注我 收藏該文 微信分享
晨楓1
粉絲 - 2 關注 - 0
+加關注
00
升級成為會員
? 上一篇: QT下多線程調用TCP的問題及可能的解決方案
? 下一篇: epoll,select,poll的區別
posted @ 2020-05-18 12:17 晨楓1 閱讀(1291) 評論(0) 編輯 收藏 舉報

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/715318.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/715318.shtml
英文地址,請注明出處:http://en.pswp.cn/news/715318.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【C語言】linux內核generic_xdp_tx

一、中文注釋 /* 在執行通用XDP時&#xff0c;我們必須繞過qdisc層和網絡挖掘點&#xff0c;* 以匹配驅動內XDP的行為。*/ void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog) {struct net_device *dev skb->dev; // 獲取skb對應的網絡設備struct netd…

面試高頻率問答題目

索引&#xff1a; 主鍵索引&#xff1a;表的id &#xff08;唯一 且 不能為空&#xff09; 唯一索引&#xff1a;表User 假設有account 字段 &#xff0c;用戶名不重復 &#xff08;唯一 可以為空&#xff09; 復合索引&#xff1a;where() 的條件 用戶名&#xff0c;密碼 …

MySQL:函數

提醒&#xff1a; 設定下面的語句是在數據庫名為 db_book里執行的。 創建user_info表 注意&#xff1a;pwd為密碼字段&#xff0c;這里使用了VARCHAR(128)類型&#xff0c;為了后面方便對比&#xff0c;開發項目里一般使用char(32)&#xff0c;SQL語句里使用MD5加密函數 USE db…

【博圖TIA-Api】通過Excel自動新建文件夾和導入FB塊

【博圖TIA-Api】通過Excel自動新建文件夾和導入FB塊 說明思路準備獲取Excel表格內文件名和FB塊名等信息新建文件夾部分篩分獲取的文件夾數據&#xff0c;去掉重復內容創建文件夾 導入FB塊導出FB塊的xml文件查找需要放置的文件夾導入塊 說明 續上一篇文章&#xff0c;這次是根據…

多線程 --- [ 線程池、線程安全、其他常見的鎖 ]

目錄 1. 線程池 模塊一&#xff1a;線程的封裝 模塊二&#xff1a;線程池的封裝 模塊三&#xff1a;互斥量的封裝 (RAII風格) 模塊四&#xff1a;任務的封裝 模塊五&#xff1a;日志的封裝 模塊六&#xff1a;時間的封裝 模塊六&#xff1a;主函數 模塊七&#xff1a…

備戰藍橋杯---狀態壓縮DP進階題1

我們來看一看一道比較難的問題&#xff08;十分十分的巧妙&#xff09;&#xff1a; 顯然我們應該一行一行放&#xff0c;又豎的會對下一行產生影響&#xff0c;我們令橫著放為0&#xff0c;豎著放的上方為1. 對于下一行&#xff0c;前一行放1的下面為0&#xff0c;但是會出現…

【Redis | 第九篇】一篇文章看懂Redis持久化機制

文章目錄 9.一篇文章看懂Redis持久化機制9.1Redis的兩種持久化機制9.1.1為什么有持久化&#xff1f; 9.2RDB機制9.2.1介紹9.2.2觸發機制&#xff08;1&#xff09;save命令觸發&#xff08;2&#xff09;bgsave命令觸發&#xff08;3&#xff09;自動觸發 9.2.3執行流程9.2.4優…

C++知識點總結(22):模擬算法真題 ★★★★☆《卡牌游戲》《移動距離》

一、卡牌游戲 1. 審題 題目描述 A , B , C A,B,C A,B,C 三人在玩一個卡牌游戲&#xff0c;規則如下&#xff1a; 游戲開始時&#xff0c; 3 3 3 人分別會得到若干張手牌, 每張牌上寫著 a&#xff0c;b&#xff0c;c 中某一個字母。手牌的順序嚴格按照輸入順序排列&#xff0c…

前端【技術類】資源學習網站整理(那些年的小網站)

學習網站整理 值得分享的視頻博主&#xff1a;學習網站鏈接 百度首頁的資源收藏里的截圖&#xff08;排列順序沒有任何意義&#xff0c;隨性而已~&#xff09;&#xff0c;可根據我標注的關鍵詞百度搜索到這些網站呀&#xff0c;本篇末尾會一一列出來&#xff0c;供大家學習呀 …

徹底搞懂回溯算法(例題詳解)

目錄 什么是回溯算法&#xff1a; 子集問題&#xff1a; 子集問題II(元素可重復但不可復選): 組合問題&#xff1a; 組合問題II(元素可重復但不可復選): 排列問題&#xff1a; 排列問題II(元素可重復但不可復選): 什么是回溯算法&#xff1a; 「回溯是遞歸的副產品&…

最小生成樹---Kruskal算法

最小生成樹定義&#xff1a; 給定一張邊帶權的無向圖 G(V,E)&#xff0c;其中 V 表示圖中點的集合&#xff0c;E 表示圖中邊的集合。 由 V 中的全部 n 個頂點和 E 中 n?1 條邊構成的無向連通子圖被稱為 G 的一棵生成樹&#xff0c;其中邊的權值之和最小的生成樹被稱為無向圖 G…

leetcode hot100 每日溫度

在本題中&#xff0c;我們是通過單調棧來解決的&#xff0c;因為我們采用了棧的數據結構&#xff0c;并且&#xff0c;棧內存儲的元素是單調的。 本題我們考慮&#xff0c;將氣溫數組元素的下標存入棧中&#xff0c;首先初始化要把0放入&#xff0c;0是下標的意思。然后我們拿…

華為HCIP Datacom H12-821 卷4

1.單選題 下面哪些策略或工具不能夠應用于 OSPF: A、access-list B、prefix-list C、route- Policy D、as-path filter 正確答案&#xff1a; D 解析&#xff1a; as-path-filter命令用來創建AS路徑過濾器&#xff0c;OSPF屬于IGP協議&#xff0c;不涉及到AS號。 2.單選題…

【python基礎學習05課_for循環以及雙重for循環】

FOR循環 一、認識循環-while 1、循環條件不能超出列表長度 當i 1&#xff0c;while i < len(lst1) 時&#xff0c;i 3后, 打印print&#xff08;lst[3]&#xff09;小宋老師&#xff0c; 繼續1, i 4, 4不小于 len(lst1)&#xff0c;打破循環。 2、循環條件超出列表長度報錯…

JMeter元件和采樣器一覽

Apache JMeter是一個強大的開源負載測試工具&#xff0c;用于性能和功能測試。JMeter提供了豐富的元件和采樣器&#xff0c;使得它能夠模擬復雜的測試場景和高并發的用戶請求。以下是JMeter中常用的一些元件和采樣器的介紹和講解&#xff1a; 測試計劃元件 測試計劃&#xff0…

latex報錯I was expecting a `,‘ or a `}‘的解決辦法

解決辦法——經過檢查在ref22后面缺少一個逗號 總結 當你在使用LaTeX時遇到“I was expecting a , or a }”這樣的錯誤&#xff0c;這通常意味著LaTeX在解析你的代碼時&#xff0c;預期在某個位置看到一個逗號&#xff08;,&#xff09;或一個大括號&#xff08;}&#xff09;…

每日一題 2369

2369. 檢查數組是否存在有效劃分 題目描述&#xff1a; 給你一個下標從 0 開始的整數數組 nums &#xff0c;你必須將數組劃分為一個或多個 連續 子數組。 如果獲得的這些子數組中每個都能滿足下述條件 之一 &#xff0c;則可以稱其為數組的一種 有效 劃分&#xff1a; 子數…

PTA 1010 一元多項式求導

1010 一元多項式求導 (25分) C/C - 知乎 (zhihu.com) #include<stdio.h> int main(){ int x,n; scanf("%d %d",&x,&n); if(n0)printf("%d %d",0,0); //n0 說明是常數&#xff0c;不需要求導 else printf("%d %…

STM32 串口通信

串口發原理 在stm32每個串口內部有發送寄存器和發送移位寄存器。 當調用HAL_UART_Transmit 時&#xff0c;cpu會將發送的數據放入發送寄存器中。發送移位寄存器會將數據轉換成電平的高低&#xff0c;從TX發出。 1、輪詢模式配置、發送與接收 輪詢模式時cpu會不斷檢測發送數…

嵌入式中匯編語言的基本實現

大家好&#xff0c;今天給大家分享&#xff0c;GNU匯編的語法。 第一&#xff1a;匯編簡介 GNU 匯編語法適用于所有的架構&#xff0c;并不是 ARM 獨享的&#xff0c;GNU 匯編由一系列的語句組成&#xff0c; 每行一條語句&#xff0c;每條語句有三個可選部分&#xff0c;如下…