2017-05-09 291 views
2

我不確定我的問題是Linux問題還是操作系統不可知論者。進程如何共享虛擬內存(Linux)

如果我有三個進程正在運行(我們稱它們爲P0,P1和P2),並且它們對於用戶來說似乎是同時運行的,它們是如何共享的?

他們各自維護自己的堆棧,堆等裏面用戶空間?

Scenario A

還是他們只是擁有整個堆,堆,等等,直到下一道工序走來,並搶佔了呢?

Scenario B

謝謝你們!

+1

看看這裏:https://www.softprayog.in/programming/interprocess-communication-using-posix-shared-memory-in-linux –

+2

物理計算機內存使用方案A中的情況。但過程不看到物理地址。每個進程都有自己的虛擬地址空間,CPU在每個內存訪問時將虛擬地址轉換爲物理地址。從進程的角度來看,它看起來像是它可以使用整個地址空間,就像場景B.請參閱:http://stackoverflow.com/questions/22290347/understanding-virtual-address-virtual-memory-and -paging – Marian

回答

4

在Linux和其他大多數當前使用的通用操作系統中,內存根本不是單個線性陣列:底層物理內存在的頁面級別使用virtual memory進行管理。

本質上,每個進程都有自己的虛擬地址空間。它大部分是空的,未映射 - 試圖訪問它導致一個segmentation fault或一般的保護違規,通常會殺死進程 - ;該進程只能訪問內核明確設置爲進程可訪問的內存。

在大多數情況下,進程無法直接訪問內核內存。要執行系統調用 - 例如,打開或讀取或寫入文件或設備 - 處理器核心本質上會執行內核模式context switch,其中內核數據結構以及用戶空間中當前進程使用的內存,可同時訪問(但不一定在內核空間中的用戶空間中的相同虛擬地址)。

這意味着,每一個過程可訪問的存儲器實際上是相當分散和不連續的時下:

╔════════╗ ╔════════╗ ╔═══════╗ 
    ║ Code ║ ║ Data ║ ║ Stack ║ 
    ╚════════╝ ╟────────╢ ╚═══════╝ 
    ╔════════╗ ║ BSS ║ 
    ║ ROdata ║ ╟────────╢ 
    ╚════════╝ ║ Heap ║ 
    ╔════════╗ ╚════════╝ 
    ║ Libs ║ 
    ╚════════╝ 

如果地址空間隨機化是在使用中,在上述各塊體的地址可以甚至從一個運行變化到下一個。通常,代碼(只讀和可執行文件)和只讀數據加載到固定地址,但動態鏈接的庫,堆棧和數據的地址不同。

沒有理由爲什麼以上其中一個應該有比另一個更高或更低的地址,所以我故意將它們彼此相鄰,而不是在一個列中!

初始化的數據和未初始化的數據通常是連續的段,只有來自可執行文件(數據段)的初始化數據部分加載。在Unix和類POSIX系統中,堆遵循未初始化的數據(並且可以使用系統調用brk()sbrk()進行擴展)。在像Linux這樣的POSIXy系統中,以及大多數其他系統中,一個進程也可以通過(匿名)內存映射增加「堆」。

進程中的初始線程也獲得一個單獨的堆棧段。任何額外的線程也將獲得他們自己的堆棧。

(學習使用POSIX線程的一個典型練習是找出進程可以創建多少個併發線程。Linux中的典型結果只有一百或幾百,很多學習者覺得這很奇怪。這種低數字的原因實際上是默認的堆棧大小,在當前的GNU/Linux桌面分佈上大概是8兆字節;單獨一百個線程的堆棧需要幾千兆字節的內存,因此併發線程的數量主要受限於可用於其堆棧的內存。非遞歸線程工作函數最多隻需要幾十千字節的堆棧,並且只需要幾行代碼即可爲新創建的pthread顯式設置堆棧大小。然後,單個進程中併發線程的最大數量通常在千位或更多的數量級上,通常取決於系統管理員設置的進程限制或缺省分配。)

正如您在上圖中沒有「操作系統」。事實上,我們確實需要將「操作系統」分成兩個完全獨立的部分:內核(它提供了在system calls中實現的功能)和庫(實現非系統調用接口可用於用戶空間處理器,通常從標準C庫開始)。

我只在上面畫了一個「Libs」(用於圖書館)框,但實際上,每個圖書館的代碼往往會得到他們自己獨立的內存片段。讓我們看看Linux中的一個特定示例(因爲這就是我現在使用的);命令cat。在Linux中,/sys/proc文件系統是特殊的僞文件系統樹,它們根本不對應任何存儲介質上的任何文件,而是由內核在訪問時構建的 - 實質上,它們是內核提供的實時視圖內核已知的數據。 /proc/self子樹包含有關「當前進程」的信息 - 即無論檢查該目錄的任何進程。 (如果不止一個同時檢查它們,它們每個只能看到它們自己的數據,因爲這不是一個正常的文件系統,而是內核創建並根據需要提供。)

/proc/self/maps(或進程ID爲PID的進程的/proc/PID/maps)僞文件描述進程具有的所有內存映射。如果我們運行cat /proc/self/maps,我們可以看到cat進程本身的映射。在我的機器(在x86-64架構運行64位Linux),它顯示

00400000-0040c000 r-xp 00000000 08:05 2359392    /bin/cat 
0060b000-0060c000 r--p 0000b000 08:05 2359392    /bin/cat 
0060c000-0060d000 rw-p 0000c000 08:05 2359392    /bin/cat 
0215f000-02180000 rw-p 00000000 00:00 0     [heap] 
7f735b70f000-7f735c237000 r--p 00000000 08:05 658950  /usr/lib/locale/locale-archive 
7f735c237000-7f735c3f6000 r-xp 00000000 08:05 1179825  /lib/x86_64-linux-gnu/libc-2.23.so 
7f735c3f6000-7f735c5f6000 ---p 001bf000 08:05 1179825  /lib/x86_64-linux-gnu/libc-2.23.so 
7f735c5f6000-7f735c5fa000 r--p 001bf000 08:05 1179825  /lib/x86_64-linux-gnu/libc-2.23.so 
7f735c5fa000-7f735c5fc000 rw-p 001c3000 08:05 1179825  /lib/x86_64-linux-gnu/libc-2.23.so 
7f735c5fc000-7f735c600000 rw-p 00000000 00:00 0 
7f735c600000-7f735c626000 r-xp 00000000 08:05 1179826  /lib/x86_64-linux-gnu/ld-2.23.so 
7f735c7fe000-7f735c823000 rw-p 00000000 00:00 0 
7f735c823000-7f735c825000 rw-p 00000000 00:00 0 
7f735c825000-7f735c826000 r--p 00025000 08:05 1179826  /lib/x86_64-linux-gnu/ld-2.23.so 
7f735c826000-7f735c827000 rw-p 00026000 08:05 1179826  /lib/x86_64-linux-gnu/ld-2.23.so 
7f735c827000-7f735c828000 rw-p 00000000 00:00 0 
7ffeea455000-7ffeea476000 rw-p 00000000 00:00 0   [stack] 
7ffeea48b000-7ffeea48d000 r--p 00000000 00:00 0   [vvar] 
7ffeea48d000-7ffeea48f000 r-xp 00000000 00:00 0   [vdso] 
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] 

前三的有代碼(r-xp),只讀數據(r--p),並初始化數據(rw-p)對於過程本身。數據段(或「堆」),該過程可使用sbrk()延伸是第三個(即,sbrk(0)將返回0x60d000。)

的方法具有一些堆,適當的,從地址0x215f000直到(但不包括)0x2180000。

下一個段是當前語言環境數據的只讀映射。 C庫將它用於區域感知接口。

接下來的四個區段是C庫正確:代碼(r-xp),常無法訪問的映射以某種方式使用/ C庫(---p)需要,只讀數據(r--p),並初始化數據(rw-p)。

下一個段和最後一列中沒有名稱的其他段,保護模式(rw-p)是獨立的數據段或堆。

接下來的三個段是Linux中使用的動態鏈接器,ld.so。再次,存在代碼段(r-xp),只讀數據段(r--p)和初始化數據段(rw-p)。

[stack]段是初始線程的堆棧。 (cat是單線程的,所以它只有一個線程。)[vvar]段由內核提供(以允許進程直接訪問某些內核提供的數據,而不必承擔系統調用的開銷)。內核提供[vdso][vsyscall]段以加速不需要完整上下文切換完成的系統調用。因此,正如你所看到的,完整的圖片比較老的C和操作系統的書籍會讓你相信的更完整的圖片更加分散,但也是免費的(比如更自由的形式)。