天天看點

記憶體管理詳解

記憶體管理是運作在計算機上的應用程式通過軟硬體協作來通路記憶體的一種方法。

記憶體管理子系統的職責為:程序請求記憶體時配置設定可用記憶體,程序釋放記憶體後回收記憶體,以及跟蹤系統中記憶體的使用狀況。

作業系統的生命周期分為兩個階段:正常執行階段和自舉階段;自舉階段使用臨時記憶體,而正常運作階段使用的記憶體有兩種情況:一種是有一部分固定的記憶體配置設定給核心代碼和資料,另一種是動态記憶體請求配置設定記憶體。

虛拟記憶體依靠透明的使用磁盤空間,得以使程式運作起來好像他們使用比系統實體記憶體更多的記憶體空間。

在使用虛拟記憶體時,程式資料被分割成基本機關,這些單元可以在磁盤與記憶體鍵來回移動。這些資料機關稱為頁

當程式從記憶體中取資料時,會從虛拟位址空間中之處需要通路的記憶體位置,每個程序都有自己獨立的虛拟位址範圍,這樣做的好處防止非法讀取或寫覆寫其他程序的資料

記憶體管理器在OS中負責維護虛拟位址和實體位址之間的關系,并且實作分頁機制。頁是基本的記憶體單元,MMU是完成實際的位址轉換工作的硬體工作。

linux頁的資料結構:

struct page{

  unsigned long flags;

  atomic_t count;

  struct list_head list;

  struct address_space * mapping;

  unsigned long index;

  struct list_head lru;

  union {

     struct pte_chain *chain;

   pte_add_r direct;

  }pte;

  void *vitrual;

.....

各個成員詳解:

count:相當于計數器,統計一個頁使用或引用的次數,數值為0表示頁是可重用的;證書表示通路該頁資料的程序數

list:是list_head結構,結構中的next和prev指針指向雙向連結清單中的對應元素

mapping: 指向每個頁關聯的address_space結構的指針

lru:存放的next和prev指針指向最近最少使用連結清單中的相應元素,這些連結清單用于頁面護手處理

記憶體管理區

記憶體管理區是由頁面(或叫實體頁)組成的,在linux存在三個記憶體管理區,ZONE_DMA(用于DMA的頁面),ZONE_NORMAL(具有虛拟映射的非DMA頁),ZONE_HIGHMEM(這些頁的位址不在虛拟位址控件中)

linux中zone的資料結構

struct zone {

        spinlock_t  lock;      //存放的是自旋鎖便是保護描述符的,該鎖保護的是記憶體管理區描述符本身

        unsigned int            compact_considered;

        unsigned long  free_pages;    //存放記憶體管理區中剩餘的空閑頁個數

        unsigned int            compact_defer_shift;

        int                     compact_order_failed;

        unsigned long           wait_table_hash_nr_entries; //與記憶體管理區上頁的程序等待隊列相關

        unsigned long           wait_table_bits;...

};

細節:緩沖對齊和區填充:緩沖對齊是為了提高對描述符中字段的通路性能,緩沖對齊通過減少複制一組資料所需的指令數量來提高性能。

頁面

頁面是存放頁的基本記憶體機關,隻要程序請求記憶體,核心便會請求一個頁面給他;當頁面不再使用,那麼核心便将其釋放。

請求頁面的函數

1 alloc_pages()和alloc_page()

alloc_page()用于請求單頁,不需要說明記憶體的大寫,__alloc_pages()是真正的處理頁面請求的函數

2. 釋放頁面的函數

宏__free_page()和free_pagge()用于釋放單頁面,在調用頁面釋放函數時,将需釋放的頁面數量參數置為0

#define  __free_page(page)  __free_pages((page), 0)

#define free_page(addr)  free_pages((addr), 0)

夥伴系統

每當頁面被配置設定和回收時,系統都會遇到名為外部碎片的記憶體碎片問題。這是由于可用頁面散布與整個記憶體空間中,即使系統可用頁面總數足夠多,但也無法配置設定大塊連續頁面。Linux使用夥伴系統的記憶體管理算法實作來達到該目的。

夥伴系統把記憶體中的空閑塊組成連結清單,每個連結清單都指向不同大小的記憶體快,大小是2的幂次方。當配置設定的塊釋放時,夥伴系統搜尋與所釋放塊大小相等的可用空閑記憶體快,如果找到相鄰的空閑塊,那麼就将他們合并成兩倍與自身大小的一個新記憶體快

程序映像的分布

當使用者空間被載入記憶體後,它就用有自己的線性位址空間,該空間被劃分成各種記憶體區或叫段。與程序相關的主要段有6個:

text:該段頁稱作代碼段,存放程式的可執行指令。mm_struct中的start_code和end_code字段儲存了text段的其實位置和結束位置

Data:該段存放所有已初始化的資料,初始化資料包含靜态配置設定的資料和初始化的全局資料

gvar:全局變量,被初始化存放在資料段中,該段具有可讀,可寫屬性。mm_struct結構的start_data和end_start字段存放資料段的起始位址和結束位址

BSS:該段存放為初始化資料。這些資料包括程式執行是被系統初始化成0的全局變量,該段的另一個名字叫做初始化為0的資料段

堆:malloc配置設定的線性位址空間,系統調用sys_brk()和brk指針移動到新位置,進而擴充了堆空間

棧:包含所有已配置設定記憶體的局部變量。mm_struct結構中的start_stack字段标記了程序棧的起始位置

他們映射到位址空間的3個記憶體區:text data stack; data段包括 data段 bss和堆

頁表

程式記憶體的有效管理是通過虛拟位址完成的。虛拟位址和對應的實體位址之間的管理便要靠核心中頁表來維護。

Linux中使用3級頁表的分頁機制:頂層目錄(pdg_t), PMD(p d_t),PTE(pte_t)

PGD存放的項指向PMD,PMD存放的相指向PTE,PTE存放的項指向特定頁面,每個程序都有自己的頁表,mm_struct->pgd指向程序的PGD

繼續閱讀