一、概述

在Linux使用中,會發現Linux的空閑內存總是非常少,讓人感覺內存總是不夠用,其實這正是Linux內存管理的特性。

能使用的內存大小和CPU位數有關,在32位的CPU上,能用的內存大小是4G,在64位CPU上,是2^64。(這裡不區分虛擬和物理)

二、分配流程

先了解內存分配的大概流程:

  1. 用戶進程使用malloc介面分配虛擬內存
  2. 用戶進程訪問內存虛擬地址
  3. MMU單元將虛擬內存轉換為物理內存
  4. MMU去內存讀取頁表
  5. MMU發現頁表不存在,自動觸發缺頁異常(page fault)
  6. 執行內核中的page fault處理程序,分配物理內存,修改頁表
  7. 異常處理完畢,返回步驟2執行相應的操作

兩個名詞概念

物理內存:對應物理上內存條上的內存(真實存在)

虛擬內存:從進程的角度看,是一個邏輯的概念(抽象存在)

三、分配細節

通過虛擬內存技術,讓每個應用程序都認為自己擁有獨立且連續的可用的內存空間(一段連續完整的地址空間),而實際上,它通常是被映射到多個物理內存段,還有部分暫時存儲在外部磁碟存儲器上,在需要時再載入到內存中來。

1、用戶進程使用什麼來進行虛擬內存的分配?

標準C庫中,提供了malloc/free函數分配釋放內存,這兩個函數底層是由brk,mmap,munmap這些系統調用實現的

  • brk是將數據段(.data)的最高地址指針_edata往高地址推;
  • mmap是在進程的虛擬地址空間中(堆和棧中間,稱為文件映射區域的地方)找一塊空閑的虛擬內存

Malloc(<128K)時使用brk進行分配,malloc(>128K)時使用mmap進行分配

2、虛擬內存和物理內存的對應關係由誰來負責維護,如何對應?

  • 頁表的創建和維護都是由操作系統內核負責的
  • 由頁表來建立虛擬內存到物理內存之間的映射關係,頁表就是在內存中的一張表,簡單看做一張hash表,記錄的是虛擬地址和物理地址的對應關係,每個虛擬地址對應一個表項,通過這張表,就能將虛擬地址轉換為物理地址,也就能建立虛擬內存到物理內存的映射關係了

3、MMU去讀取頁表,那它是如何知道頁表在哪的?

  • CPU上有特別的寄存器(CR3),向其中寫入頁表的地址,MMU就知道了

4、每個進程都有自己的頁表,那MMU怎麼知道讀取哪張?

  • 操作系統在初始化或分配、釋放內存時會執行一些指令在物理內存中填寫頁表,然後用指令設置MMU,告訴MMU頁表在物理內存中的什麼位置。

5、為啥頁表會不存在呢?頁表是何時創建的?

  • 在完成虛擬地址的分配後,這塊內存一般是沒有物理頁與之對應的(即沒有頁表),等到進程第一次讀寫A這塊內存的時候,發生缺頁中斷(page fault)

6、page fault是如何創建頁表的?

  • page fault是硬體上的一種機制,當硬體檢測到缺頁異常時,主動觸發,然後會自動跳轉到異常處理程序處理。該異常處理程序是內核中提前註冊好的,其中要做的主要操作,就是:分配物理內存,然後修改相應進程的頁表,建立該物理內存和虛擬內存的映射關係(頁表項)。異常跟中斷類似,區別在於,中斷是非同步的,由外設觸發;異常是同步的,由CPU自己觸發

四、開機時內存分配

開機時禁止了內存分頁機制,這和原始的MS-DOS一樣,只有1MB的可用存儲地址空間,用戶可以運行任何指令、也可以修改存儲區域中的任何位置——在實模式中沒有保護和特權指令的概念。

雖然在剛剛開機後只能使用1MB的存儲地址空間,但是32位的Intel處理器第一條執行指令地址為0xFFFFFFF0(4GB存儲空間的最後16位元組)

五、開機後內存分配

內存可用大小是和位數有關,以32位來說,操作系統將虛擬空間劃分為兩部分,一部分為內核空間,一部分為用戶空間。

對linux操作系統而言,將最高的1G位元組(從虛擬地址0xC0000000到0xFFFFFFFF),供內核使用,稱為內核空間,而將較低的3G位元組(從虛擬地址0x00000000到0xBFFFFFFF),供各個進程使用,稱為用戶空間。

PS:

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

六、MMU

  • 作用

內存管理單元作用:VA映射成PA

  • 頁/頁幀/頁表/頁表項(PTE)

MMU是負責把虛擬地址映射為物理地址,但凡"映射"都要解決兩個問題:映射的最小單位(粒度)和映射的規則。

單位:MMU中VA到PA映射的最小單位稱為頁(Page),映射的最低粒度是單個虛擬頁到物理頁,頁大小通常是4K。

頁幀:是指物理內存中的一頁內存,MMU虛實地址映射就是尋找物理頁幀的過程。

頁表:描述MMU的映射規則,即虛擬內存哪(幾)個頁映射到物理內存哪(幾)個頁幀。頁表由一條條代表映射規則的記錄組成。頁表存儲在內存中。

頁表項:即頁表中的每一條規則稱為一個頁表條目。

  • TLB

由於頁表存儲在內存中,MMU去訪問內存中的頁表很慢,所以就有了TLB(Translation Lookaside Buffers)。

就是MMU內部專用的存放頁表的cache,保存著最近使用的PTE乃至全部頁表。MMU接收到虛擬地址後,首先在TLB中查找,如果找到該VA對應的PTE就直接轉換,找不到再去外存頁表查找,並置換進TLB。TLB屬於片上SRAM,訪問速度快,通過TLB緩存PTE可以節省MMU訪問外存頁表的時間,從而加速虛實地址轉換。

七、參考

閑聊Linux內存管理(1)?

happyseeker.github.io

Linux內存分配的原理--malloc/brk/mmap?

vinoit.me
圖標
硬體篇之MMU - CSDN博客?

blog.csdn.net
圖標

推薦閱讀:

相關文章