極客時間Linux操作系統(二)內存管理

一,內存管理

1,操作系統的內存管理分爲三部分:

  • 物理內存的管理
  • 虛擬內存的管理
  • 虛擬地址和物理地址如何映射

2,虛擬空間分爲兩部分:

  • 內核空間
  • 用戶空間

  • Text segment存放二進制可執行代碼的位置
  • data segment存放靜態常量
  • bss segment存放未初始化的靜態變量
  • 堆動態內存分配,往高地址增長
  • memory mapping segment:文件映射進內存,比如動態庫
  • 棧往低地址增長

總結:

  1. 虛擬內存空間的管理,每個進程看到的都是獨立的,互不干擾的虛擬地址空間
  2. 物理內存的管理,物理內存地址只有內存管理模塊能夠使用
  3. 內存映射,需要將虛擬內存和物理內存映射、關聯起來

3,分段管理

(1)分段機制

  • 虛擬地址 = 段選擇子(段寄存器) + 段內偏移量
  • 段選擇子 = 段號(段表索引) + 標識位
  • 段表 = 物理基地址 + 段界限(偏移量範圍) + 特權等級

如果要訪問段2中偏移量600的虛擬地址,我們可以計算出物理地址=段2的基地址2000+偏移量600=2600

(2)Linux 分段實現

 

  • 段表稱爲段描述符表, 放在全局標識符表GDT中
  • Linux 將段基地址都初始化爲 0, 並沒有使用段的全部功能,不用於地址映射
  • Linux 分段功能主要用於權限檢查

4,Linux 通過分頁實現映射

  • 物理內存被換分爲大小固定(4KB)的頁, 物理頁可在內存與硬盤間換出/換入,提高內存的利用率

  • 頁表 = 虛擬頁號 + 物理頁號; 用於定位頁
  • 虛擬地址 = 虛擬頁號 + 頁內偏移

  •  若採用單頁表, 32位系統中一個頁表將有 1M 頁表項, 佔用 4MB(每項 4B)
  • Linux 32位系統採用兩級頁表: 頁表目錄(1K項, 10bit) + 頁表(1K項, 10bit) + (頁大小(4KB, 12bit)),正好對應32位
  • 映射 4GB 內存理論需要 1K 個頁表目錄項 + 1K*1K=1M 頁表項, 將佔用 4KB+4MB 空間
  • 因爲完整的頁表目錄可以滿足所有地址的查詢, 因此頁表只需在對應地址有內存分配時才生成;
  • linux64 位系統採用 4 級頁表

採用兩級頁表的好處

總結:

  1. 虛擬內存空間的管理,將虛擬地址分成大小相等的頁;
  2. 物理內存的管理,將物理內存分成大小相等的頁;
  3. 內存映射,將虛擬內存和物理內存映射起來,並且在內存緊張的時候可以換出到磁盤

二,進程空間管理

  • 內存管理信息在 task_struct 的 mm_struct 中
  • task_size 指定用戶態虛擬地址大小。32 位系統:3G 用戶態, 1G 內核態。64 位系統(只利用 48 bit 地址): 128T 用戶態; 128T 內核態

(1)用戶態地址空間佈局和管理

  • mm_struct 中有映射頁的統計信息(總頁數, 鎖定頁數, 數據/代碼/棧映射頁數等)以及各區域地址,用戶態區域佈局如下圖

  • mm_struct中還有 vm_area_struct 描述各個區域(代碼/數據/棧等)的屬性(包含起始/終止地址, 可做的操作等), 通過鏈表和紅黑樹管理

(2)內核地址空間佈局和管理

  • 所有進程看到的內核虛擬地址空間是同一個
  •  32 位系統, 前 896MB 爲直接映射區(虛擬地址 - 3G = 物理地址),直接映射區也需要建立頁表, 通過虛擬地址訪問(除了內存管理模塊),直接映射區組成: 1MB 啓動時佔用; 然後是內核代碼/全局變量/BSS等,即 內核 ELF文件內容; 進程 task_struct 即內核棧也在其中,896MB 也稱爲高端內存(指物理內存),剩餘虛擬空間組成: 8MB 空餘; 內核動態映射空間(動態分配內存, 映射放在內核頁表中); 持久內存映射(儲存物理頁信息); 固定內存映射; 臨時內存映射(例如爲進程映射文件時使用)
  • 64 位系統: 8T 空餘; 64T 直接映射區域; 32T(動態映射); 1T(物理頁描述結構 struct page); 512MB(內核代碼, 也採用直接映射)

三,物理內存管理

(1)物理內存組織方式

  • 每個物理頁由 struct page 表示
  • 物理頁連續, page 放入一個數組中, 稱爲平坦內存模型,多個 CPU 通過總線訪問內存, 稱爲 SMP 對稱多處理器(採用平坦內存模型, 總線成爲瓶頸)
  • 每個 CPU 都有本地內存, 訪問內存不用總線, 稱爲 NUMA 非一致內存訪問,本地內存稱爲 NUMA 節點, 本地內存不足可以向其他節點申請,NUMA 採用非連續內存模型,頁號不連續

(2)節點

  • 用 pglist_data 表示 NUMA 節點,每個節點分成一個個區域zone,多個節點信息保存在 node_data 數組中
  • pglist_data 包括 id,page 數組,起始頁號, 總頁數, 可用頁數
  • 節點分爲多個區域 zone, 包括 DMA; 直接映射區; 高端內存區; 可移動區(避免內存碎片)

  • 區域 zone,包含第一個頁頁號; 區域總頁數; 區域實際頁數; 被夥伴系統管理的頁數; 用 per_cpu_pageset 區分冷熱頁(熱頁, 被 CPU 緩存的頁)

(3)頁

  • 用 struct page 表示, 有多種使用模式, 因此 page 結構體多由 union 組成
  1. 使用一整個頁: 1) 直接和虛擬地址映射(匿名頁); 2) 與文件關聯再與虛擬地址映射(內存映射文件);page 記錄: 標記用於內存映射; 指向該頁的頁表數; 換出頁的鏈表; 複合頁, 用於合成大頁;
  2. 分配小塊內存:Linux 採用 slab allocator 技術; 申請一整頁, 分爲多個小塊存儲池, 用隊列維護其狀態(較複雜);slub allocator 更簡單;slob allocator 用於嵌入式; page 記錄: 第一個 slab 對象; 空閒列表; 待釋放列表

(4)頁分配

  • 分配較大內存(頁級別), 使用夥伴系統
  •  Linux 把空閒頁分組爲 11 個頁塊鏈表, 鏈表管理大小不同的頁塊(頁大小 2^i * 4KB)

  • 分配大頁剩下的內存, 插入對應空閒鏈表

總結:

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章