1. 程式人生 > >作業系統——虛擬記憶體管理

作業系統——虛擬記憶體管理

面試問題彙總:

1.邏輯地址、線性地址,實體地址,虛擬地址分別是什麼

實體地址,CPU地址匯流排傳來的地址,實體地址中很大一部分是留給記憶體條中的記憶體的

線性地址Linear Address)也叫虛擬地址(virtual address)是邏輯地址到實體地址變換之間的中間層。在分段部件中邏輯地址是段中的偏移地址,然後加上基地址就是線性地址。

邏輯地址是在有地址變換功能的計算機中,訪內指令給出的地址 (運算元) 叫邏輯地址,也叫相對地址,也就是是機器語言指令中,用來指定一個運算元或是一條指令的地址。要經過定址方式的計算或變換才得到記憶體儲器中的實際有效地址即實體地址。一個邏輯地址由兩部份組成,段識別符號: 段內偏移量。段識別符號是由一個16位長的欄位組成,稱為段選擇符。


2. 段式管理和頁式管理的優缺點?

3.Linux中的物理和虛擬儲存空間佈局

http://blog.csdn.net/tianyahaijiaozd/article/details/6784239

1. Linux中虛擬地址與實體地址之間的轉換


80386中邏輯地址到實體地址的轉換分為兩步:1.段轉換(segment convert):邏輯地址轉換為線性地址;2.頁轉換(page convert):線性地址轉換為實體地址

段轉換:首先根據sector找到descriptor table(GDT)中對應的位置,找到描述符descriptor,每個descriptor項中有base,LIMIT,Type,DPL等,根據base找到該段的起始地址(線性地址中),然後加上offset,得到線性地址

頁轉換:線性地址的前10位是page dircetory中的索引位置,page directory中存放了page table的實體地址,根據線性地址的第二個10位可以得其在page table中的索引位置,加上page table的實體地址,可以得到該地址的PTE。PTE中記錄了該地址對應的實體地址

2.全域性描述符表GDT和區域性描述符表LDT

1.概況

80386體系結構中地址的轉換(邏輯地址--->實體地址)分為兩個階段:

(1) logical address --------> linear address(segment translation)

(2) linear address ---------> physical address (page translation) [optional]

如果沒有頁轉換,那麼線性地址就是實體地址(例如boot loader在開啟page translation之前,線性地址就是實體地址)

段地址轉換的過程中需要使用到全域性描述符表GDT(Global Destriptor Table)和區域性描述符表LDT(Local Destriptor Table)

A descriptor table is simply a memory array of 8-byte entries that contain descriptors

logical addresss |------selector-----|----------offset----------------|

邏輯地址的selector用於索引描述符表中的entry,每個entry為8B,加上基地址,便可以得到描述符表的位置,並取其中的內容,得到段地址的位置

2.GDT和LDT以及兩者的關係

GDT(Global Destriptor Table):每個cpu對應一個GDT,它可以存放在記憶體中的任何位置,但入口地址(基地址)存放在register(GDTR)中,程式設計師可以使用LGDT和SGDT進行load 和 store GDT的入口地址

LDT(Local Destriptor Table):每個process一個LDT,入口地址存放在register(LDTR)中,程式設計師可以只用LLDT和SLDT進行load和store

兩者的關係:

可以將GDT理解為一級描述符表,LDT為二級描述符表,(類似一級頁表和二級頁表),每個程序的LDT也是一段記憶體,因此它也有一個段描述符,這個描述符就存放在GDT中

每個程序都有自己的程式段,資料段,heap段,stack段,有了LDT,可以將每個程序的code segment, data segment, heap segment, stack segment封裝在一起,通過尋找GDT中的不同進行的LDT的位置,然後改變LDTR,便可以實現不同程序見的切換

3.段暫存器(Segment Register)

cs(cose segment), ss, DS(data segment), ES, FS, GS,使用段暫存器的目的是避免程序每次訪問地址時都需要進行記憶體訪問


實體地址就是實際的實體記憶體的地址,邏輯地址是程式指令使用的地址。頁表的作用就是實現邏輯地址到實體地址的對映。

x86的32位地址,前20位用於查詢頁表

3.頁表和頁表項

TLB作用

由於頁表存放在主存中,因此程式每次訪存至少需要兩次:一次訪存獲取實體地址,第二次訪存才獲得資料。想像一下x86_32架構下沒有TLB的存在時的情況,對線性地址的訪問,首先從PGD中獲取PTE(第一次記憶體訪問),在PTE中獲取頁框地址(第二次記憶體訪問),最後訪問實體地址,總共需要3次RAM的訪問。

如果有TLB存在,並且TLB hit,那麼只需要一次RAM訪問即可。當cpu要訪問一個虛擬地址/線性地址時,CPU會首先根據虛擬地址的高20位(20是x86特定的,不同架構有不同的值)在TLB中查詢。如果是表中沒有相應的表項,稱為TLB miss,需要通過訪問慢速RAM中的頁表計算出相應的實體地址。同時,實體地址被存放在一個TLB表項中,以後對同一線性地址的訪問,直接從TLB表項中獲取實體地址即可,稱為TLB hit

TLB內部存放的基本單位是頁表條目,對應著RAM中存放的頁表條目。頁表條目的大小固定不變的,所以TLB容量越大,所能存放的頁表條目越多,TLB hit的機率也越大。但是TLB容量畢竟是有限的,因此RAM頁表和TLB頁表條目無法做到一一對應。因此CPU收到一個線性地址,那麼必須快速做兩個判斷:

1 所需的也表示否已經快取在TLB內部(TLB miss或者TLB hit)

2 所需的頁表在TLB的哪個條目內



4.地址的保護機制

保護主要包括以下幾點:

  • 程序不允許修改其只讀文字段
  • 不允許它讀或修改任何核心中的程式碼和資料結構
  • 不允許它它讀或者寫其他程序的私有儲存器
  • 不允許修改與其他程序共享的虛擬頁面,除非所有的共享者顯示地允許它這麼做

5.缺頁中斷過程

發成缺頁中斷後,執行了那些操作?

當一個程序發生缺頁中斷的時候,程序會陷入核心態,執行以下操作

1、檢查要訪問的虛擬地址是否合法 

2、查詢/分配一個物理頁 

3、填充物理頁內容(讀取磁碟,或者直接置0,或者啥也不幹)

4、建立對映關係(虛擬地址到實體地址) 


6.Linux中虛擬儲存器的實現

task_struct中有一個條目mm_struct,它描述了虛擬儲存器的當前狀態。pgd和mmap兩個變數,pgd指向page directory,mmap指向一個vm_area_structs(區域結構,段)的連結串列,其中每個vm_area_structs都描述了當前虛擬地址的一個區域。當核心執行該程序時,它就將pgd存放在CR3控制暫存器中

vm_area_structs中:vm_start, vm_end,..

6.動態儲存器分配

1.malloc, vmalloc, kmalloc的區別

  1. kmalloc和vmalloc是分配的是核心的記憶體,malloc分配的是使用者的記憶體
  2. kmalloc保證分配的記憶體在物理上是連續的,vmalloc保證的是在虛擬地址空間上的連續,malloc不保證任何東西(這點是自己猜測的,不一定正確)
  3. kmalloc能分配的大小有限,vmalloc和malloc能分配的大小相對較大
  4. 記憶體只有在要被DMA訪問的時候才需要物理上連續
  5. vmalloc比kmalloc要慢

2.malloc分配器演算法

(1)如何實現malloc和free,slab演算法,buddy演算法

(3) Malloc在什麼情況下呼叫mmap?

從作業系統角度來看,程序分配記憶體有兩種方式,分別由兩個系統呼叫完成:brk和mmap(不考慮共享記憶體)。brk是將資料段(.data)的最高地址指標_edata往高地址推,mmap是在程序的虛擬地址空間中(一般是堆和棧中間)找一塊空閒的。這兩種方式分配的都是虛擬記憶體,沒有分配實體記憶體。在第一次訪問已分配的虛擬地址空間的時候,發生缺頁中斷,作業系統負責分配實體記憶體,然後建立虛擬記憶體和實體記憶體之間的對映關係。

在標準C庫中,提供了malloc/free函式分配釋放記憶體,這兩個函式底層是由brk,mmap,munmap這些系統呼叫實現的。