搜尋
首頁運維linux運維詳解虛擬記憶體管理

詳解虛擬記憶體管理

Jun 20, 2017 am 11:23 AM
記憶體管理虛擬

  現代作業系統普遍採用虛擬記憶體管理(Virtual Memory Management)機制,這需要處理器中的MMU(Memory Management Unit,記憶體管理單元)提供支援。首先引入 PA 和 VA 兩個概念。

1.PA(Physical Address)---物理位址

  如果處理器沒有MMU,或者有MMU但沒有啟用,CPU執行單元發出的記憶體位址將直接傳送到晶片引腳上,被內存晶片(以下稱為物理內存,以便與虛擬內存區分)接收,這稱為PA(Physical Address,以下簡稱PA),如下圖所示。

詳解虛擬記憶體管理

實體位址

2.VA(Virtual Address)---虛擬位址

  如果處理器啟用了MMU,CPU執行單元發出的記憶體位址將被MMU截獲,從CPU到MMU的位址稱為虛擬位址(Virtual Address,以下簡稱VA),而MMU將這個位址翻譯成另一個位址發到CPU晶片的外部位址接腳上,也就是將VA映射成PA,如下圖所示。

詳解虛擬記憶體管理

虛擬位址

  如果是32位元處理器,則內位址匯流排是32位元的,與CPU執行單元相連(圖中只是示意性地畫了4條位址線),而經過MMU轉換之後的外位址匯流排則不一定是32位的。也就是說,虛擬位址空間和實體位址空間是獨立的,32位元處理器的虛擬位址空間是4GB,而實體位址空間既可以大於也可以小於4GB。

  MMU將VA對應到PA是以頁(Page)為單位的,32位元處理器的頁尺寸通常是4KB。例如,MMU可以透過一個映射項目將VA的一頁0xb7001000~0xb7001fff對應到PA的一頁0x2000~0x2fff,如果CPU執行單元要存取虛擬位址0xb7001008,則實際存取到的實體位址是0x2008。實體記憶體中的頁稱為實體頁面或頁幀(Page Frame)。虛擬記憶體的哪個頁面對應到實體記憶體的哪個頁幀是透過頁表(Page Table)來描述的,頁表保存在實體記憶體中,MMU會尋找頁表來決定一個VA應該對應到什麼PA。

 

3. 進程位址空間

詳解虛擬記憶體管理進程位址空間

 

  x86平台的虛擬位址空間是0x0000 0000~0xffff ffff,大致上前3GB(0x0000 0000~0xbfff ffff)是用戶空間,後1GB(0xc000 000ffff~0xffffffff,ffff~0xffff ffff~0xffff。

   Text Segmest 和 Data Segment

  • Text Segment,包含.text段、.rodata段、.plt段等。是從/bin/bash載入到記憶體的,存取權限為r-x。

  • Data Segment,包含.data段、.bss段等。也是從/bin/bash載入到記憶體的,存取權限為rw-。

     堆疊和堆疊

  • 堆(heap):堆說白了就是電腦記憶體中的剩餘空間,malloc函數動態分配記憶體是在這裡分配的。在動態分配記憶體時堆空間是可以成長到高位址的。堆空間的位址上限稱為Break,堆空間要向高位址成長就要抬高Break,映射新的虛擬記憶體頁面到物理內存,這是透過系統呼叫brk實現的,malloc函數也是呼叫brk向核心請求分配內存的。

  • #堆疊(stack):堆疊是一個特定的記憶體區域,其中高位址的部分保存著進程的環境變數和命令列參數,低位址的部分保存函數棧幀,棧空間是向低地址增長的,但顯然沒有堆空間那麼大的可供增長的餘地,因為實際的應用程序動態分配大量內存的並不少見,但是有幾十層深的函數呼叫並且每層呼叫都有很多局部變數的非常少見。

  如果寫程式的時候沒有註意好記憶體的分配問題,在堆疊和堆疊這兩個地方可能產生以下幾個問題:

  1. 記憶體洩漏:如果你在一個函數裡透過malloc 在堆裡申請了一塊空間,並在堆疊中聲明一個指標變數保存它,那麼當該函數結束時,該函數的成員變量將會被釋放,包括這個指標變量,那麼這塊空間也就找不回來了,也就無法得到釋放。久而久之,可能造成下面的記憶體外洩問題。

  2. 堆疊溢位:如果你放太多資料到堆疊中(例如大型的結構體和陣列),那麼就可能會造成「堆疊溢位」( Stack Overflow)問題,程式也會終止。為了避免這個問題,在聲明這類變數時應使用 malloc 申請堆的空間。

  3. 野指標 與 段錯誤:如果一個指標所指向的空間已經被釋放,此時再試圖用該指標存取已經被釋放了的空間將會造成「段錯誤」(Segment Fault)問題。此時指針已經變成野指針,應該及時手動將野指針置空。

4. 虛擬記憶體管理的作用

  1. 虛擬記憶體管理可以控制實體記憶體的存取權。實體記憶體本身是不限制存取的,任何位址都可以讀寫,而作業系統要求不同的頁面具有不同的存取權限,這是利用CPU模式和MMU的記憶體保護機制實現的。

  2. 虛擬記憶體管理最主要的作用是讓每個行程有獨立的位址空間。所謂獨立的地址空間是指,不同進程中的同一個VA被MMU映射到不同的PA,並且在某一個進程中訪問任何地址都不可能訪問到另外一個進程的數據,這樣使得任何一個進程由於執行錯誤指令或惡意程式碼導致的非法記憶體存取不會意外改寫其它進程的數據,不會影響其它進程的運行,從而保證整個系統的穩定性。另一方面,每個行程都認為自己獨佔整個虛擬位址空間,這樣連結器和載入器的實作會比較容易,不必考慮各行程的位址範圍是否衝突。

詳解虛擬記憶體管理是独立的

進程位址空間是獨立的

  1. VA到PA的對映會給分配和釋放內存帶來方便,物理位址不連續的幾塊記憶體可以映射成虛擬位址連續的一塊記憶體。例如要用malloc分配一塊很大的內存空間,雖然有足夠多的空閒物理內存,卻沒有足夠大的連續空閒內存,這時就可以分配多個不連續的物理頁面而映射到連續的虛擬地址範圍。

詳解虛擬記憶體管理

不連續的PA可以對應為連續的VA

  1. 一個系統如果同時運行著很多進程,為各進程分配的內存總和可能會大於實際可用的物理內存,虛擬內存管理使得這種情況下各進程仍然能夠正常運行。因為各進程分配的只不過是虛擬記憶體的頁面,這些頁面的資料可以映射到實體頁面,也可以暫時保存到磁碟上而不佔用實體頁面,在磁碟上臨時保存虛擬記憶體頁面的可能是磁碟分割區,也可能是磁碟文件,稱為交換設備(Swap Device)。 當實體記憶體不夠用時,將一些不常用的實體頁面中的資料暫時儲存到交換裝置,然後這個實體頁面就認為是空閒的了,可以重新分配給行程使用,這個過程稱為換出(Page out)。如果進程要用到被換出的頁面,就從交換設備再載入回物理內存,這稱為換入(Page in)。換出和換入操作統稱為換頁(Paging),因此:

    #系統中可分配的記憶體總量=實體記憶體的大小+交換裝置的大小

#如下圖所示。第一張圖是換出,將實體頁面中的資料儲存到磁碟,並解除位址映射,釋放實體頁面。第二張圖是換入,從空閒的實體頁面中分配一個,將磁碟暫存的頁面載入回內存,並建立位址映射。

詳解虛擬記憶體管理

換頁

5.malloc 和free

C標準函式庫函數malloc可以在堆空間動態分配內存,它的底層透過brk系統呼叫向作業系統申請記憶體。動態分配的記憶體用完之後可以用free釋放,更準確地說是歸還給malloc,這樣下次呼叫malloc時這塊記憶體可以再被分配。

1 #include <stdlib.h>2 void *malloc(size_t size);  //返回值:成功返回所分配内存空间的首地址,出错返回NULL3 void free(void *ptr);</stdlib.h>
#

malloc的参数size表示要分配的字节数,如果分配失败(可能是由于系统内存耗尽)则返回NULL。由于malloc函数不知道用户拿到这块内存要存放什么类型的数据,所以返回通用指针void *,用户程序可以转换成其它类型的指针再访问这块内存。malloc函数保证它返回的指针所指向的地址满足系统的对齐要求,例如在32位平台上返回的指针一定对齐到4字节边界,以保证用户程序把它转换成任何类型的指针都能用。

动态分配的内存用完之后可以用free释放掉,传给free的参数正是先前malloc返回的内存块首地址。

示例

举例如下:

 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 typedef struct { 5     int number; 6     char *msg; 7 } unit_t; 8 int main(void) 9 {10     unit_t *p = malloc(sizeof(unit_t));11     if (p == NULL) {12         printf("out of memory\n");13         exit(1);14     }15     p->number = 3;16     p->msg = malloc(20);17     strcpy(p->msg, "Hello world!");18     printf("number: %d\nmsg: %s\n", p->number, p->msg);19     free(p->msg);20     free(p);21     p = NULL;22     return 0;23 }</string.h></stdlib.h></stdio.h>

 

说明

  • unit_t *p = malloc(sizeof(unit_t));这一句,等号右边是void *类型,等号左边是unit_t *类型,编译器会做隐式类型转换,我们讲过void *类型和任何指针类型之间可以相互隐式转换。

  • 虽然内存耗尽是很不常见的错误,但写程序要规范,malloc之后应该判断是否成功。以后要学习的大部分系统函数都有成功的返回值和失败的返回值,每次调用系统函数都应该判断是否成功。

  • free(p);之后,p所指的内存空间是归还了,但是p的值并没有变,因为从free的函数接口来看根本就没法改变p的值,p现在指向的内存空间已经不属于用户,换句话说,p成了野指针,为避免出现野指针,我们应该在free(p);之后手动置p = NULL;

  • 应该先free(p->msg),再free(p)。如果先free(p),p成了野指针,就不能再通过p->msg访问内存了。

6.内存泄漏

  如果一个程序长年累月运行(例如网络服务器程序),并且在循环或递归中调用malloc分配内存,则必须有free与之配对,分配一次就要释放一次,否则每次循环都分配内存,分配完了又不释放,就会慢慢耗尽系统内存,这种错误称为内存泄漏(Memory Leak)。另外,malloc返回的指针一定要保存好,只有把它传给free才能释放这块内存,如果这个指针丢失了,就没有办法free这块内存了,也会造成内存泄漏。例如:

1 void foo(void)2 {3     char *p = malloc(10);4     ...5 }

  foo函數回傳時要釋放局部變數p的記憶體空間,它所指向的記憶體位址就遺失了,這10個位元組也就沒辦法釋放了。記憶體洩漏的Bug很難找到,因為它不會像訪問越界一樣導致程式運行錯誤,少量記憶體洩漏並不影響程式的正確運行,大量的記憶體洩漏會使系統記憶體緊缺,導致頻繁換頁,不僅影響當前進程,而且把整個系統拖得很慢。

  關於malloc和free還有一些特殊情況。 malloc(0)這種呼叫也是合法的,也會傳回一個非NULL的指針,這個指標也可以傳給free釋放,但不能透過這個指標存取記憶體。 free(NULL)也是合法的,不做任何事情,但是free一個野指標是不合法的,例如先呼叫malloc回傳一個指標p,然後連著呼叫兩次free(p);,則後一次呼叫會產生運行時錯誤。

 

以上是詳解虛擬記憶體管理的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
Linux中的維護模式:何時以及為什麼使用它Linux中的維護模式:何時以及為什麼使用它Apr 25, 2025 am 12:15 AM

使用Linux維護模式的時機和原因:1)系統啟動問題時,2)進行重大系統更新或升級時,3)執行文件系統維護時。維護模式提供安全、控制的環境,確保操作的安全性和效率,減少對用戶的影響,並增強系統的安全性。

Linux:基本命令和操作Linux:基本命令和操作Apr 24, 2025 am 12:20 AM

Linux中不可或缺的命令包括:1.ls:列出目錄內容;2.cd:改變工作目錄;3.mkdir:創建新目錄;4.rm:刪除文件或目錄;5.cp:複製文件或目錄;6.mv:移動或重命名文件或目錄。這些命令通過與內核交互執行操作,幫助用戶高效管理文件和系統。

Linux操作:管理文件,目錄和權限Linux操作:管理文件,目錄和權限Apr 23, 2025 am 12:19 AM

在Linux中,文件和目錄管理使用ls、cd、mkdir、rm、cp、mv命令,權限管理使用chmod、chown、chgrp命令。 1.文件和目錄管理命令如ls-l列出詳細信息,mkdir-p遞歸創建目錄。 2.權限管理命令如chmod755file設置文件權限,chownuserfile改變文件所有者,chgrpgroupfile改變文件所屬組。這些命令基於文件系統結構和用戶、組系統,通過系統調用和元數據實現操作和控制。

Linux中的維護模式是什麼?解釋了Linux中的維護模式是什麼?解釋了Apr 22, 2025 am 12:06 AM

MaintenancemodeInuxisAspecialBootenvironmentforforcalsystemmaintenancetasks.itallowsadMinistratorStoperFormTaskSlikerSettingPassingPassingPasswords,RepairingFilesystems,andRecoveringFrombootFailuresFailuresFailuresInamInimAlenimalenimalenrenmentrent.ToEnterMainterMainterMaintErmaintErmaintEncemememodeBoode,Interlecttheboo

Linux:深入研究其基本部分Linux:深入研究其基本部分Apr 21, 2025 am 12:03 AM

Linux的核心組件包括內核、文件系統、Shell、用戶空間與內核空間、設備驅動程序以及性能優化和最佳實踐。 1)內核是系統的核心,管理硬件、內存和進程。 2)文件系統組織數據,支持多種類型如ext4、Btrfs和XFS。 3)Shell是用戶與系統交互的命令中心,支持腳本編寫。 4)用戶空間與內核空間分離,確保系統穩定性。 5)設備驅動程序連接硬件與操作系統。 6)性能優化包括調整系統配置和遵循最佳實踐。

Linux體系結構:揭示5個基本組件Linux體系結構:揭示5個基本組件Apr 20, 2025 am 12:04 AM

Linux系統的五個基本組件是:1.內核,2.系統庫,3.系統實用程序,4.圖形用戶界面,5.應用程序。內核管理硬件資源,系統庫提供預編譯函數,系統實用程序用於系統管理,GUI提供可視化交互,應用程序利用這些組件實現功能。

Linux操作:利用維護模式Linux操作:利用維護模式Apr 19, 2025 am 12:08 AM

Linux的維護模式可以通過GRUB菜單進入,具體步驟為:1)在GRUB菜單中選擇內核並按'e'編輯,2)在'linux'行末添加'single'或'1',3)按Ctrl X啟動。維護模式提供了一個安全環境,適用於系統修復、重置密碼和系統升級等任務。

Linux:如何進入恢復模式(和維護)Linux:如何進入恢復模式(和維護)Apr 18, 2025 am 12:05 AM

進入Linux恢復模式的步驟是:1.重啟系統並按特定鍵進入GRUB菜單;2.選擇帶有(recoverymode)的選項;3.在恢復模式菜單中選擇操作,如fsck或root。恢復模式允許你以單用戶模式啟動系統,進行文件系統檢查和修復、編輯配置文件等操作,幫助解決系統問題。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器