内核页表和进程页表
初學內核時,經常被“內核頁表”和“進程頁表”搞暈,不知道這到底是個啥東東,跟我們平時理解的頁表有和關系。。
內核頁表:即書上說的主內核頁表,在內核中其實就是一段內存,存放在主內核頁全局目錄init_mm.pgd(swapper_pg_dir)中,硬件并不直接使用。
進程頁表:每個進程自己的頁表,放在進程自身的頁目錄task_struct.pgd中。
在保護模式下,從硬件角度看,其運行的基本對象為“進程”(或線程),而尋址則依賴于“進程頁表”,在進程調度而進行上下文切換時,會進行頁表的切換:即將新進程的pgd(頁目錄)加載到CR3寄存器中。從這個角度看,其實是完全沒有用到“內核頁表”的,那么“內核頁表”有什么用呢?跟“進程頁表”有什么關系呢?
1、內核頁表中的內容為所有進程共享,每個進程都有自己的“進程頁表”,“進程頁表”中映射的線性地址包括兩部分:
用戶態
內核態
其中,內核態地址對應的相關頁表項,對于所有進程來說都是相同的(因為內核空間對所有進程來說都是共享的),而這部分頁表內容其實就來源于“內核頁表”,即每個進程的“進程頁表”中內核態地址相關的頁表項都是“內核頁表”的一個拷貝。
2、“內核頁表”由內核自己維護并更新,在vmalloc區發生page fault時,將“內核頁表”同步到“進程頁表”中。以32位系統為例,內核頁表主要包含兩部分:
線性映射區
vmalloc區
其中,線性映射區即通過TASK_SIZE偏移進行映射的區域,對32系統來說就是0-896M這部分區域,映射對應的虛擬地址區域為TASK_SIZE-TASK_SIZE+896M。這部分區域在內核初始化時就已經完成映射,并創建好相應的頁表,即這部分虛擬內存區域不會發生page fault。
vmalloc區,為896M-896M+128M,這部分區域用于映射高端內存,有三種映射方式:vmalloc、固定、臨時,這里就不像述了。。
以vmalloc為例(最常使用),這部分區域對應的線性地址在內核使用vmalloc分配內存時,其實就已經分配了相應的物理內存,并做了相應的映射,建立了相應的頁表項,但相關頁表項僅寫入了“內核頁表”,并沒有實時更新到“進程頁表中”,內核在這里使用了“延遲更新”的策略,將“進程頁表”真正更新推遲到第一次訪問相關線性地址,發生page fault時,此時在page fault的處理流程中進行“進程頁表”的更新
內核頁表:即書上說的主內核頁表,在內核中其實就是一段內存,存放在主內核頁全局目錄init_mm.pgd(swapper_pg_dir)中,硬件并不直接使用。
進程頁表:每個進程自己的頁表,放在進程自身的頁目錄task_struct.pgd中。
在保護模式下,從硬件角度看,其運行的基本對象為“進程”(或線程),而尋址則依賴于“進程頁表”,在進程調度而進行上下文切換時,會進行頁表的切換:即將新進程的pgd(頁目錄)加載到CR3寄存器中。從這個角度看,其實是完全沒有用到“內核頁表”的,那么“內核頁表”有什么用呢?跟“進程頁表”有什么關系呢?
1、內核頁表中的內容為所有進程共享,每個進程都有自己的“進程頁表”,“進程頁表”中映射的線性地址包括兩部分:
用戶態
內核態
其中,內核態地址對應的相關頁表項,對于所有進程來說都是相同的(因為內核空間對所有進程來說都是共享的),而這部分頁表內容其實就來源于“內核頁表”,即每個進程的“進程頁表”中內核態地址相關的頁表項都是“內核頁表”的一個拷貝。
2、“內核頁表”由內核自己維護并更新,在vmalloc區發生page fault時,將“內核頁表”同步到“進程頁表”中。以32位系統為例,內核頁表主要包含兩部分:
線性映射區
vmalloc區
其中,線性映射區即通過TASK_SIZE偏移進行映射的區域,對32系統來說就是0-896M這部分區域,映射對應的虛擬地址區域為TASK_SIZE-TASK_SIZE+896M。這部分區域在內核初始化時就已經完成映射,并創建好相應的頁表,即這部分虛擬內存區域不會發生page fault。
vmalloc區,為896M-896M+128M,這部分區域用于映射高端內存,有三種映射方式:vmalloc、固定、臨時,這里就不像述了。。
以vmalloc為例(最常使用),這部分區域對應的線性地址在內核使用vmalloc分配內存時,其實就已經分配了相應的物理內存,并做了相應的映射,建立了相應的頁表項,但相關頁表項僅寫入了“內核頁表”,并沒有實時更新到“進程頁表中”,內核在這里使用了“延遲更新”的策略,將“進程頁表”真正更新推遲到第一次訪問相關線性地址,發生page fault時,此時在page fault的處理流程中進行“進程頁表”的更新
總結
- 上一篇: linux内存管理——kmalloc和v
- 下一篇: poll模型