程序—記憶體描述符(mm_struct)
一、概述
記憶體描述符的結構體——mm_struct,抽象的來描述linux下程序的地址空間的所有的資訊。
一個程序的虛擬地址空間主要由兩個資料結來描述。一個是最高層次的:mm_struct,一個是較高層次的:vm_area_structs。最高層次的mm_struct結構描述了一個程序的整個虛擬地址空間。較高層次的結構vm_area_truct描述了虛擬地址空間的一個區間(簡稱虛擬區)。每個程序只有一個mm_struct結構,在每個程序的task_struct結構中,有一個指向該程序的結構。可以說,mm_struct結構是對整個使用者空間的描述。
首先,我們來定位mm_struct檔案所在位置和task_struct所在路徑是一樣的,不過他們所在檔案是不一樣的,mm_struct所在的檔案是mm_types.h,接下來我們就來分析這個結構好了。
首先我們來看下這個:
這就是我們所說的由task_struct到mm_struct,程序的地址空間的分佈。
每一個程序都會有自己獨立的mm_struct,這樣每一個程序都會有自己獨立的地址空間,這樣才能互不干擾。當程序之間的地址空間被共享的時候,我們可以理解為這個時候是多個程序使用一份地址空間,這就是執行緒。
其實多個程序的地址空間分佈就是上面這張圖一樣,每一個程序的使用者空間在32位的平臺上就是上面這個圖的情況,對於實體記憶體當中的核心kernel,是隻存在一份,所有的程序是用來共享的,核心當中會利用PCB(程序控制塊)來管理不同的程序。對於linux的體系結構來說,linux當中為了保護虛擬核心空間不被修改,所以linux體系結構是這樣的:
這種三層的體系結構,保證程序只能對最外面的應用程式進行修改,保證了記憶體的安全性。
另外,我們從第一張圖上可以發射線,每個區域是依靠著兩個指標進行維護的,比如[start_data,end_data)是用來維護data段,[start_code,end_data)用來維護code段,[start_brk,brk),用來維護heap和heap的指標。[start_stack,end_stack)是用來維護stack段空間範圍。mmap_base是維護共享對映區的起始地址。bss段表示的是所有的未初始化的全域性變數,為了效率,對處在bss段的變數,將它們匿名對映到“零頁”,這樣提高了程式的載入效率。
1 //指向線性區物件的連結串列頭
2 struct vm_area_struct * mmap; /* list of VMAs */
3 //指向線性區物件的紅黑樹
4 struct rb_root mm_rb;
在地址空間中,mmap為地址空間的記憶體區域(用vm_area_struct結構來表示)連結串列,mm_rb用紅黑樹來儲存,連結串列表示起來更加方便,紅黑樹表示起來更加方便查詢。區別是,當虛擬區較少的時候,這個時候採用單鏈表,由mmap指向這個連結串列,當虛擬區多時此時採用紅黑樹的結構,由mm_rb指向這棵紅黑樹。這樣就可以在大量資料的時候效率更高。所有的mm_struct結構體通過自身的mm_list域連結在一個雙向連結串列上,該連結串列的首元素是init_mm記憶體描述符,代表init程序的地址空間。
1 atomic_t mm_users;
2 atomic_t mm_count;
這兩個內容表示的各有不同。
使用mm_users和mm_count兩個計數器是為了區別主使用計數器和使用該地址空間的程序的數目。
每一個程序都可以被別的程序來共享,也就是和別的程序來共享mm_struct.
所有的mm_struct結構以連結串列的形式存在的。
另外需要說明的就是kernel執行緒是沒有地址空間的,也就沒有對應的mm_struct,kernel執行緒使用之前執行的程序的記憶體描述符。
程式中通常用到的地址常常具有區域性性,當前最近一次用蛋糕的虛擬地址區間很可能下一次還是需要用到,所以我們採用區域性性原理,通常時候我們去吧當前地址周圍一個區間的記憶體放入快取記憶體當中,這個區間在mm_struct當中就是由mmap_cache來維護。
二、關於頁表
linux kernel 使用記憶體管理的時候,採取的是頁式的管理方式,應用程式給出的記憶體地址是虛擬地址,是經過若干層的頁表的轉換才能得到真正的實體地址,所以相對來說,程序的地址空間是一份虛擬的地址空間,每一個地址通過頁表的轉換對映到所謂的實體地址空間上。在這裡所共享的1G的kernel在記憶體地址是隻存一份的,但是對於每一個程序其他的3G的空間,是儲存其他不同的東西,另外,頁表具有許可權限定,這樣也就提供給了每塊記憶體區域,比如我定義了:
1 char * p="12342";
這裡的“12342”是一個常量字串,它被存放在只讀常量儲存區,所以這個區域的頁表的屬性就是隻讀,這樣就可以高效的維護整個程序的地址空間。
每一個程序都會有一個程序描述符,task_struct,task_strust當中的mm指標指向每個程序的記憶體描述符,而對於每個mm,有都會有單獨的頁表,
pgt區間是用來維護頁表的目錄,每一個程序的都有自己的頁表目錄,需要注意程序的頁目錄和核心的頁目錄是不一樣的,當程式排程器排程程式執行的時候,這個時候這個地址就會轉換成為實體地址,linux一般採用三級頁表進行轉換。
三、task_struct和mm_strcuct的聯絡
不知道你是否還記得在task_struct當中的
1 //關於程序的地址空間,指向程序的地址空間。(連結串列和紅黑樹)
2 struct mm_struct *mm, *active_mm;
task_struct和mm_strcut通過這兩個成員進行聯絡,每一個程序都會有唯一的mm_struct結構體。
1 struct mm_struct {
2
3 //指向線性區物件的連結串列頭
4 struct vm_area_struct * mmap; /* list of VMAs */
5 //指向線性區物件的紅黑樹
6 struct rb_root mm_rb;
7 //指向最近找到的虛擬區間
8 struct vm_area_struct * mmap_cache; /* last find_vma result */
9
10 //用來在程序地址空間中搜索有效的程序地址空間的函式
11 unsigned long (*get_unmapped_area) (struct file *filp,
12 unsigned long addr, unsigned long len,
13 unsigned long pgoff, unsigned long flags);
14
15 unsigned long (*get_unmapped_exec_area) (struct file *filp,
16 unsigned long addr, unsigned long len,
17 unsigned long pgoff, unsigned long flags);
18
19 //釋放線性區時呼叫的方法,
20 void (*unmap_area) (struct mm_struct *mm, unsigned long addr);
21
22 //標識第一個分配檔案記憶體對映的線性地址
23 unsigned long mmap_base; /* base of mmap area */
24
25
26 unsigned long task_size; /* size of task vm space */
27 /*
28 * RHEL6 special for bug 790921: this same variable can mean
29 * two different things. If sysctl_unmap_area_factor is zero,
30 * this means the largest hole below free_area_cache. If the
31 * sysctl is set to a positive value, this variable is used
32 * to count how much memory has been munmapped from this process
33 * since the last time free_area_cache was reset back to mmap_base.
34 * This is ugly, but necessary to preserve kABI.
35 */
36 unsigned long cached_hole_size;
37
38 //核心程序搜尋程序地址空間中線性地址的空間空間
39 unsigned long free_area_cache; /* first hole of size cached_hole_size or larger */
40
41 //指向頁表的目錄
42 pgd_t * pgd;
43
44 //共享程序時的個數
45 atomic_t mm_users; /* How many users with user space? */
46
47 //記憶體描述符的主使用計數器,採用引用計數的原理,當為0時代表無使用者再次使用
48 atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */
49
50 //線性區的個數
51 int map_count; /* number of VMAs */
52
53 struct rw_semaphore mmap_sem;
54
55 //保護任務頁表和引用計數的鎖
56 spinlock_t page_table_lock; /* Protects page tables and some counters */
57
58 //mm_struct結構,第一個成員就是初始化的mm_struct結構,
59 struct list_head mmlist; /* List of maybe swapped mm's. These are globally strung
60 * together off init_mm.mmlist, and are protected
61 * by mmlist_lock
62 */
63
64 /* Special counters, in some configurations protected by the
65 * page_table_lock, in other configurations by being atomic.
66 */
67
68 mm_counter_t _file_rss;
69 mm_counter_t _anon_rss;
70 mm_counter_t _swap_usage;
71
72 //程序擁有的最大頁表數目
73 unsigned long hiwater_rss; /* High-watermark of RSS usage */、
74 //程序線性區的最大頁表數目
75 unsigned long hiwater_vm; /* High-water virtual memory usage */
76
77 //程序地址空間的大小,鎖住無法換頁的個數,共享檔案記憶體對映的頁數,可執行記憶體對映中的頁數
78 unsigned long total_vm, locked_vm, shared_vm, exec_vm;
79 //使用者態堆疊的頁數,
80 unsigned long stack_vm, reserved_vm, def_flags, nr_ptes;
81 //維護程式碼段和資料段
82 unsigned long start_code, end_code, start_data, end_data;
83 //維護堆和棧
84 unsigned long start_brk, brk, start_stack;
85 //維護命令列引數,命令列引數的起始地址和最後地址,以及環境變數的起始地址和最後地址
86 unsigned long arg_start, arg_end, env_start, env_end;
87
88 unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */
89
90 struct linux_binfmt *binfmt;
91
92 cpumask_t cpu_vm_mask;
93
94 /* Architecture-specific MM context */
95 mm_context_t context;
96
97 /* Swap token stuff */
98 /*
99 * Last value of global fault stamp as seen by this process.
100 * In other words, this value gives an indication of how long
101 * it has been since this task got the token.
102 * Look at mm/thrash.c
103 */
104 unsigned int faultstamp;
105 unsigned int token_priority;
106 unsigned int last_interval;
107
108 //線性區的預設訪問標誌
109 unsigned long flags; /* Must use atomic bitops to access the bits */
110
111 struct core_state *core_state; /* coredumping support */
112 #ifdef CONFIG_AIO
113 spinlock_t ioctx_lock;
114 struct hlist_head ioctx_list;
115 #endif
116 #ifdef CONFIG_MM_OWNER
117 /*
118 * "owner" points to a task that is regarded as the canonical
119 * user/owner of this mm. All of the following must be true in
120 * order for it to be changed:
121 *
122 * current == mm->owner
123 * current->mm != mm
124 * new_owner->mm == mm
125 * new_owner->alloc_lock is held
126 */
127 struct task_struct *owner;
128 #endif
129
130 #ifdef CONFIG_PROC_FS
131 /* store ref to file /proc/<pid>/exe symlink points to */
132 struct file *exe_file;
133 unsigned long num_exe_file_vmas;
134 #endif
135 #ifdef CONFIG_MMU_NOTIFIER
136 struct mmu_notifier_mm *mmu_notifier_mm;
137 #endif
138 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
139 pgtable_t pmd_huge_pte; /* protected by page_table_lock */
140 #endif
141 /* reserved for Red Hat */
142 #ifdef __GENKSYMS__
143 unsigned long rh_reserved[2];
144 #else
145 /* How many tasks sharing this mm are OOM_DISABLE */
146 union {
147 unsigned long rh_reserved_aux;
148 atomic_t oom_disable_count;
149 };
150
151 /* base of lib map area (ASCII armour) */
152 unsigned long shlib_base;
153 #endif
154 };
四、轉載於
https://blog.csdn.net/qq_26768741/article/details/54375524
本文來自部落格園,作者:Mr-xxx,轉載請註明原文連結:https://www.cnblogs.com/MrLiuZF/p/15150009.html