Linux系統硬體模塊之內存
一、概述
在Linux使用中,會發現Linux的空閑內存總是非常少,讓人感覺內存總是不夠用,其實這正是Linux內存管理的特性。
能使用的內存大小和CPU位數有關,在32位的CPU上,能用的內存大小是4G,在64位CPU上,是2^64。(這裡不區分虛擬和物理)
二、分配流程
先了解內存分配的大概流程:
- 用戶進程使用malloc介面分配虛擬內存
- 用戶進程訪問內存虛擬地址
- MMU單元將虛擬內存轉換為物理內存
- MMU去內存讀取頁表
- MMU發現頁表不存在,自動觸發缺頁異常(page fault)
- 執行內核中的page fault處理程序,分配物理內存,修改頁表
- 異常處理完畢,返回步驟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位元組)