虛擬地址空間布局架構(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;//堆 堆疊的起始地址





未完待續
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/298950.html
標籤:其他
