虛拟位址空間布局架構(Linux核心學習)
1.Linux核心整體架構及子系統
核心對下管理硬體,對上通過運作時庫對應用提供服務
-
使用者空間
使用
配置設定記憶體通過malloc()
釋放記憶體free()
-
核心空間
虛拟程序負責從程序的虛拟位址空間配置設定虛拟頁,
來擴大或收縮堆,sys_brk
sys_mmap
負責在記憶體映射區配置設定虛拟頁,
頁配置設定器負責配置設定實體頁
不連續記憶體配置設定器提供配置設定記憶體的接口
和釋放記憶體接口vmalloc
vfree
,申請連續的實體頁的成功率比較低,可以申請不連續的實體頁,r然後映射到連續的虛拟頁,及虛拟位址連續而實體位址不連續
記憶體控制組來控制程序占用的資源,當記憶體碎片化的時候,找不到連續的實體頁,記憶體碎片整理通過遷移方式得到連續的實體頁,當記憶體不足的時候,負責回收實體頁
-
硬體
MMU1包含一個頁表緩存,儲存最近使用過的頁表映射,避免每次都要查詢虛拟頁對應的實體頁,解決了CPU執行速度與記憶體速度不比對的問題
來個例子:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
constexpr int MAX = 1024;
int main(int argc, char const *argv[])
{
/*
sbrk函數在核心的管理下将虛拟位址空間映射到記憶體,供malloc函數使用。
*/
void *p = sbrk(0);
void *old = p;
p = (int *)sbrk(MAX * MAX);
if (p == (void *)(-1))
{
std::cout << "sbrk error\n";
exit(0);
}
printf("old:%p\tp=%p\n", p, old);
void *new_ = sbrk(0);
printf("new:%p", new_);
sbrk(-MAX * MAX);
return 0;
}
輸出
old:0x55555557a000 p=0x55555557a000
new:0x55555567a000
可見成功配置設定了新的記憶體.
那我們如何更加具體的看到是否擷取了記憶體呢?
更改代碼如下:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
constexpr int MAX = 1024;
int main(int argc, char const *argv[])
{
/*
sbrk函數在核心的管理下将虛拟位址空間映射到記憶體,供malloc函數使用。
*/
void *p = sbrk(0);
void *old = p;
p = (int *)sbrk(MAX * MAX);
if (p == (void *)(-1))
{
std::cout << "sbrk error\n";
exit(0);
}
printf("old:%p\tp=%p\n", p, old);
void *new_ = sbrk(0);
printf("new:%p\n", new_);
printf("pid= %d\n", getpid());
while (true)
{
}
sbrk(-MAX * MAX);
return 0;
}
運作,不要停止
輸出為:
old:0x55555557a000 p=0x55555557a000
new:0x55555567a000
pid= 1193
打開新終端輸入
cat /proc/1193/maps
(一切皆檔案)檢視記憶體情況:
後續就不在示範了(懶)
2.虛拟記憶體空間記憶體架構
linux-4.4.4\arch\arm64\include\asm\memory.h
#define TASK_SIZE_64 (UL(1) << VA_BITS)//64位作業系統 //VA_BITS 編譯核心的時候選擇的虛拟位址的位數
#ifdef CONFIG_COMPAT
#define TASK_SIZE_32 UL(0x100000000) //32位作業系統
程序的使用者虛拟位址空間包含區域:代碼段、資料段、未初始化資料段;
動态庫的代碼段、資料段和未初始化資料段;存放動态生成的資料的堆;
存放局部變量和實作函數調用的棧;
把檔案區間映射到虛拟位址空間的記憶體映射區域;存放在棧底部的環境變量和參數字元串。
部分核心代碼:
struct mm_struct {
struct vm_area_struct *mmap;//虛拟記憶體區域連結清單 /* list of VMAs */
struct rb_root mm_rb;//虛拟記憶體區紅黑樹
u32 vmacache_seqnum; /* per-thread vmacache */
#ifdef CONFIG_MMU //在記憶體映射區找到一個沒有映射的區域
unsigned long (*get_unmapped_area) (struct file *filp,
unsigned long addr, unsigned long len,
unsigned long pgoff, unsigned long flags);
unsigned long mmap_base; //記憶體映射區起始位址 /* base of mmap area */
unsigned long mmap_legacy_base; /* base of mmap area in bottom-up allocations */
unsigned long task_size; //使用者虛拟空間長度 /* size of task vm space */
unsigned long highest_vm_end; /* highest vma end address */
pgd_t * pgd;
atomic_t mm_users; //共享一個使用者虛拟空間的程序數量,程序包含的線程的數量 /* How many users with user space? */
atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */
atomic_long_t nr_ptes;
unsigned long hiwater_rss;//程序所擁有的最大頁框數 /* High-watermark of RSS usage */
unsigned long hiwater_vm; // 最大頁數/* High-water virtual memory usage */
unsigned long total_vm; //程序頁數 /* Total pages mapped */
unsigned long locked_vm;//鎖住不能交換的頁數 /* Pages that have PG_mlocked set */
unsigned long pinned_vm; /* Refcount permanently increased */
unsigned long shared_vm; /* Shared pages (files) */
unsigned long exec_vm; /* VM_EXEC & ~VM_WRITE */
unsigned long stack_vm; /* VM_GROWSUP/DOWN */
unsigned long def_flags;
unsigned long start_code, end_code, start_data, end_data;//代碼段起始結束,資料段起始結束
unsigned long start_brk, brk, start_stack;//堆 棧的起始位址