九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
進程地址空間

虛擬內(nèi)存管理 

我們知道操作系統(tǒng)利用體系結(jié)構(gòu)提供的VA到PA的轉(zhuǎn)換機制實現(xiàn)虛擬內(nèi)存管理。有了共享庫的基礎(chǔ)知識之后,現(xiàn)在我們可以進一步理解虛擬內(nèi)存管理了。首先分析一個例子:

$ ps  PID TTY          TIME CMD29977 pts/0    00:00:00 bash30032 pts/0    00:00:00 ps$ cat /proc/29977/maps 08048000-080f4000 r-xp 00000000 08:15 688142     /bin/bash080f4000-080f9000 rw-p 000ac000 08:15 688142     /bin/bash080f9000-080fe000 rw-p 080f9000 00:00 0 09283000-09497000 rw-p 09283000 00:00 0          [heap]b7ca8000-b7cb2000 r-xp 00000000 08:15 581665     /lib/tls/i686/cmov/libnss_files-2.8.90.sob7cb2000-b7cb3000 r--p 00009000 08:15 581665     /lib/tls/i686/cmov/libnss_files-2.8.90.sob7cb3000-b7cb4000 rw-p 0000a000 08:15 581665     /lib/tls/i686/cmov/libnss_files-2.8.90.so...b7e15000-b7f6d000 r-xp 00000000 08:15 581656     /lib/tls/i686/cmov/libc-2.8.90.sob7f6d000-b7f6f000 r--p 00158000 08:15 581656     /lib/tls/i686/cmov/libc-2.8.90.sob7f6f000-b7f70000 rw-p 0015a000 08:15 581656     /lib/tls/i686/cmov/libc-2.8.90.so...b7fbd000-b7fd7000 r-xp 00000000 08:15 565466     /lib/ld-2.8.90.sob7fd7000-b7fd8000 r-xp b7fd7000 00:00 0          [vdso]b7fd8000-b7fd9000 r--p 0001a000 08:15 565466     /lib/ld-2.8.90.sob7fd9000-b7fda000 rw-p 0001b000 08:15 565466     /lib/ld-2.8.90.sobfac5000-bfada000 rw-p bffeb000 00:00 0          [stack]

ps命令查看當(dāng)前終端下的進程,得知bash進程的id是29977,然后用cat /proc/29977/maps命令查看它的虛擬地址空間。/proc目錄中的文件并不是真正的磁盤文件,而是由內(nèi)核虛擬出來的文件系統(tǒng),當(dāng)前系統(tǒng)中運行的每個進程在/proc下都有一個子目錄,目錄名就是進程的id,查看目錄下的文件可以得到該進程的相關(guān)信息。此外,用pmap 29977命令也可以得到類似的輸出結(jié)果。

圖 20.4. 進程地址空間


第 4 節(jié) “MMU”講過,x86平臺的虛擬地址空間是0x0000 0000~0xffff ffff,大致上前3GB(0x0000 0000~0xbfff ffff)是用戶空間,后1GB(0xc000 0000~0xffff ffff)是內(nèi)核空間,在這里得到了印證。0x0804 8000-0x080f 4000是從/bin/bash加載到內(nèi)存的,訪問權(quán)限為r-x,表示Text Segment,包含.text段、.rodata段、.plt段等。0x080f 4000-0x080f 9000也是從/bin/bash加載到內(nèi)存的,訪問權(quán)限為rw-,表示Data Segment,包含.data段、.bss段等。

0x0928 3000-0x0949 7000不是從磁盤文件加載到內(nèi)存的,這段空間稱為堆(Heap),以后會講到用malloc函數(shù)動態(tài)分配內(nèi)存是在這里分配的。從0xb7ca 8000開始是共享庫的映射空間,每個共享庫也分為幾個Segment,每個Segment有不同的訪問權(quán)限??梢钥吹?,從堆空間的結(jié)束地址(0x0949 7000)到共享庫映射空間的起始地址(0xb7ca 8000)之間有很大的地址空洞,在動態(tài)分配內(nèi)存時堆空間是可以向高地址增長的。堆空間的地址上限(0x09497000)稱為Break,堆空間要向高地址增長就要抬高Break,映射新的虛擬內(nèi)存頁面到物理內(nèi)存,這是通過系統(tǒng)調(diào)用brk實現(xiàn)的,malloc函數(shù)也是調(diào)用brk向內(nèi)核請求分配內(nèi)存的。

/lib/ld-2.8.90.so就是動態(tài)鏈接器/lib/ld-linux.so.2,后者是前者的符號鏈接。標(biāo)有[vdso]的地址范圍是linux-gate.so.1的映射空間,我們講過這個共享庫是由內(nèi)核虛擬出來的。0xbfac 5000-0xbfad a000是??臻g,其中高地址的部分保存著進程的環(huán)境變量和命令行參數(shù),低地址的部分保存函數(shù)棧幀,??臻g是向低地址增長的,但顯然沒有堆空間那么大的可供增長的余地,因為實際的應(yīng)用程序動態(tài)分配大量內(nèi)存的并不少見,但是有幾十層深的函數(shù)調(diào)用并且每層調(diào)用都有很多局部變量的非常少見??傊?,??臻g是可能用盡的,并且比堆空間更容易用盡,在第 3 節(jié) “遞歸”講過,無窮遞歸會用盡??臻g最終導(dǎo)致段錯誤。

虛擬內(nèi)存管理起到了什么作用呢?可以從以下幾個方面來理解。

第一,虛擬內(nèi)存管理可以控制物理內(nèi)存的訪問權(quán)限。物理內(nèi)存本身是不限制訪問的,任何地址都可以讀寫,而操作系統(tǒng)要求不同的頁面具有不同的訪問權(quán)限,這是利用CPU模式和MMU的內(nèi)存保護機制實現(xiàn)的。例如,Text Segment被只讀保護起來,防止被錯誤的指令意外改寫,內(nèi)核地址空間也被保護起來,防止在用戶模式下執(zhí)行錯誤的指令意外改寫內(nèi)核數(shù)據(jù)。這樣,執(zhí)行錯誤指令或惡意代碼的破壞能力受到了限制,頂多使當(dāng)前進程因段錯誤終止,而不會影響整個系統(tǒng)的穩(wěn)定性。

第二,虛擬內(nèi)存管理最主要的作用是讓每個進程有獨立的地址空間。所謂獨立的地址空間是指,不同進程中的同一個VA被MMU映射到不同的PA,并且在某一個進程中訪問任何地址都不可能訪問到另外一個進程的數(shù)據(jù),這樣使得任何一個進程由于執(zhí)行錯誤指令或惡意代碼導(dǎo)致的非法內(nèi)存訪問都不會意外改寫其它進程的數(shù)據(jù),不會影響其它進程的運行,從而保證整個系統(tǒng)的穩(wěn)定性。另一方面,每個進程都認為自己獨占整個虛擬地址空間,這樣鏈接器和加載器的實現(xiàn)會比較容易,不必考慮各進程的地址范圍是否沖突。

繼續(xù)前面的實驗,再打開一個終端窗口,看一下這個新的bash進程的地址空間,可以發(fā)現(xiàn)和先前的bash進程地址空間的布局差不多:

$ ps  PID TTY          TIME CMD30697 pts/1    00:00:00 bash30749 pts/1    00:00:00 ps$ cat /proc/30697/maps08048000-080f4000 r-xp 00000000 08:15 688142     /bin/bash080f4000-080f9000 rw-p 000ac000 08:15 688142     /bin/bash080f9000-080fe000 rw-p 080f9000 00:00 0 082d7000-084f9000 rw-p 082d7000 00:00 0          [heap]b7cf1000-b7cfb000 r-xp 00000000 08:15 581665     /lib/tls/i686/cmov/libnss_files-2.8.90.sob7cfb000-b7cfc000 r--p 00009000 08:15 581665     /lib/tls/i686/cmov/libnss_files-2.8.90.sob7cfc000-b7cfd000 rw-p 0000a000 08:15 581665     /lib/tls/i686/cmov/libnss_files-2.8.90.so...b7e5e000-b7fb6000 r-xp 00000000 08:15 581656     /lib/tls/i686/cmov/libc-2.8.90.sob7fb6000-b7fb8000 r--p 00158000 08:15 581656     /lib/tls/i686/cmov/libc-2.8.90.sob7fb8000-b7fb9000 rw-p 0015a000 08:15 581656     /lib/tls/i686/cmov/libc-2.8.90.so...b8006000-b8020000 r-xp 00000000 08:15 565466     /lib/ld-2.8.90.sob8020000-b8021000 r-xp b8020000 00:00 0          [vdso]b8021000-b8022000 r--p 0001a000 08:15 565466     /lib/ld-2.8.90.sob8022000-b8023000 rw-p 0001b000 08:15 565466     /lib/ld-2.8.90.sobff0e000-bff23000 rw-p bffeb000 00:00 0          [stack]

該進程也占用了0x0000 0000-0xbfff ffff的地址空間,Text Segment也是0x0804 8000-0x080f 4000,Data Segment也是0x080f 4000-0x080f 9000,和先前的進程一模一樣,因為這些地址是在編譯鏈接時寫進/bin/bash這個可執(zhí)行文件的,兩個進程都加載它。這兩個進程在同一個系統(tǒng)中同時運行著,它們的Data Segment占用相同的VA,但是兩個進程各自干各自的事情,顯然Data Segment中的數(shù)據(jù)應(yīng)該是不同的,相同的VA怎么會有不同的數(shù)據(jù)呢?因為它們被映射到不同的PA。如下圖所示。

圖 20.5. 進程地址空間是獨立的


從圖中還可以看到,兩個進程都是bash進程,Text Segment是一樣的,并且Text Segment是只讀的,不會被改寫,因此操作系統(tǒng)會安排兩個進程的Text Segment共享相同的物理頁面。由于每個進程都有自己的一套VA到PA的映射表,整個地址空間中的任何VA都在每個進程自己的映射表中查找相應(yīng)的PA,因此不可能訪問到其它進程的地址,也就沒有可能意外改寫其它進程的數(shù)據(jù)。

另外,注意到兩個進程的共享庫加載地址并不相同,共享庫的加載地址是在運行時決定的,而不是寫在/bin/bash這個可執(zhí)行文件中。但即使如此,也不影響兩個進程共享相同物理頁面中的共享庫,當(dāng)然,只有只讀的部分是共享的,可讀可寫的部分不共享。

使用共享庫可以大大節(jié)省內(nèi)存。比如libc,系統(tǒng)中幾乎所有的進程都映射libc到自己的進程地址空間,而libc的只讀部分在物理內(nèi)存中只需要存在一份,就可以被所有進程共享,這就是“共享庫”這個名稱的由來了。

現(xiàn)在我們也可以理解為什么共享庫必須是位置無關(guān)代碼了。比如libc,不同的進程雖然共享libc所在的物理頁面,但這些物理頁面被映射到各進程的虛擬地址空間時卻位于不同的地址,所以要求libc的代碼不管加載到什么地址都能正確執(zhí)行。

第三,VA到PA的映射會給分配和釋放內(nèi)存帶來方便,物理地址不連續(xù)的幾塊內(nèi)存可以映射成虛擬地址連續(xù)的一塊內(nèi)存。比如要用malloc分配一塊很大的內(nèi)存空間,雖然有足夠多的空閑物理內(nèi)存,卻沒有足夠大的連續(xù)空閑內(nèi)存,這時就可以分配多個不連續(xù)的物理頁面而映射到連續(xù)的虛擬地址范圍。如下圖所示。

圖 20.6. 不連續(xù)的PA可以映射為連續(xù)的VA


第四,一個系統(tǒng)如果同時運行著很多進程,為各進程分配的內(nèi)存之和可能會大于實際可用的物理內(nèi)存,虛擬內(nèi)存管理使得這種情況下各進程仍然能夠正常運行。因為各進程分配的只不過是虛擬內(nèi)存的頁面,這些頁面的數(shù)據(jù)可以映射到物理頁面,也可以臨時保存到磁盤上而不占用物理頁面,在磁盤上臨時保存虛擬內(nèi)存頁面的可能是一個磁盤分區(qū),也可能是一個磁盤文件,稱為交換設(shè)備(Swap Device)。當(dāng)物理內(nèi)存不夠用時,將一些不常用的物理頁面中的數(shù)據(jù)臨時保存到交換設(shè)備,然后這個物理頁面就認為是空閑的了,可以重新分配給進程使用,這個過程稱為換出(Page out)。如果進程要用到被換出的頁面,就從交換設(shè)備再加載回物理內(nèi)存,這稱為換入(Page in)。換出和換入操作統(tǒng)稱為換頁(Paging),因此:

系統(tǒng)中可分配的內(nèi)存總量 = 物理內(nèi)存的大小 + 交換設(shè)備的大小

如下圖所示。第一張圖是換出,將物理頁面中的數(shù)據(jù)保存到磁盤,并解除地址映射,釋放物理頁面。第二張圖是換入,從空閑的物理頁面中分配一個,將磁盤暫存的頁面加載回內(nèi)存,并建立地址映射。

圖 20.7. 換頁

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
linux內(nèi)存管理淺析
請求頁式存儲管理的頁面置換算法
linux 內(nèi)存回收機制 [free 命令例子]
Cortex-M可以跑Linux操作系統(tǒng)嗎?
Linux進程的虛擬地址空間
分頁池和非分頁池
更多類似文章 >>
生活服務(wù)
熱點新聞
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服