Re: [問題] memory stack 的問題
※ 引述《kyuudonut (善良老百姓)》之銘言:
: 最近在研讀virtual memory相關知識,大致上了解paging的運作模式
: [問題二] 如果有多個 process 同時運作,各自 stack 的起始位置又是如何分配呢?
: (一直往下長不會撞到嗎@@)
: (當某 process 需要的 stack 大小超過兩個 page 又是如何維護?
: page 如果不連續怎麼辦?)
你既然是在讀 virtual memeory,應該知道每個 process 都有自己一塊虛擬位址空間。
以 32-bit 系統來說,就是每個 process 各自有 4GB 的定址空間。
這 4GB 的定址空間,再細一點的分法是再區分成 user space 跟 kernel space。
預設的狀況下,Windows 是 2GB/2GB,Linux 則是 3GB/1GB。
有些人在 32-bit 的 XP 插了很大記憶體的顯示卡,結果記憶體剩下 2.xx GB,
原因就是這樣來的,因為 kernel space 要劃一塊去映射,細節要問熟微軟系統的。
stack 和 heap 這些東西都在 user space,user space 是各 process 之間獨立的。
換句話說對每個 32-bit Linux process 而言,那 3GB 裡不會有其它 process 的資料。
所以沒有什麼撞到的問題,兩個平行世界的東西你要怎麼讓它們相撞?
如果要 programmer 去擔心這種事,那 virtual memory 存在的意義就沒有了。
你沒特別設定的話,同個編譯系統生出來的執行檔,在同個 OS 執行,
每個 process 的 stack 起始位址都是一模一樣的,當然這不會是實體位址。
stack 的 page 當然是連續的。
在每個 process 各自獨立的虛擬 3GB 定址空間裡,有什麼理由劃不出連續空間?
你 C 程式裡 pointer 看到的記憶體位址都是這些虛擬位址,並不是實體的。
至於這些 page 怎麼對應到實體記憶體的 frame,我想書上應該都寫得很清楚了。
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 220.132.55.117
※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1472449011.A.2A3.html
※ 編輯: tinlans (220.132.55.117), 08/29/2016 13:48:13
→
08/29 16:53, , 1F
08/29 16:53, 1F
→
08/29 16:53, , 2F
08/29 16:53, 2F
→
08/29 21:14, , 3F
08/29 21:14, 3F
→
08/29 21:14, , 4F
08/29 21:14, 4F
推
08/29 23:15, , 5F
08/29 23:15, 5F
→
08/29 23:16, , 6F
08/29 23:16, 6F
我知道的部分是有點老了,而且是 BSD malloc 的實作,因為我是 FreeBSD 派的。
不過還是能大概回一下你的問題,因為概念基本上都通。
這 4GB 空間不是你 pointer 隨便玩都行,還是有它的規矩在。
OS 課本上寫的記憶體保護原理實際上也有作用,所以你沒跟 OS 申請依然是非法存取。
BSD libc 會知道目前 heap size,如果 process 呼叫 malloc() 時,
如果 heap 必須長大才能滿足需求,必須呼叫 sbrk() 這個 system call。
這個 system call 如果 return -1 表示失敗,因此 OS 可以在這裡拒絕配置記憶體。
sbrk() 做的事情是移動 data segment 的 break 位址,break 的意義手冊上查得到:
The brk() and sbrk() functions are used to change the amount of memory
allocated in a process's data segment. They do this by moving the loca-
tion of the "break". The break is the first address after the end of the
process's uninitialized data segment (also known as the "BSS").
簡單來說,把 break 往高位址移動就是給這 process 更多 memory 的意思。
OS 沒有 heap 的概念,它把 data + heap 當成一個 data segment 整體。
如果你隨便把 sbrk 這關鍵字丟 Google 圖片搜尋,應該會看到這種圖:
http://flylib.com/books/2/830/1/html/2/images/09fig9_3.jpg

使用 sbrk() 要求更多記憶體,就等同於把 break 上推,也等於 heap 往上長大。
如果沒推上去就摸更上面的記憶體,下場大家也很熟悉,就是 segmentation fault。
某一年開始 FreeBSD 的手冊加入了這兩行:
The brk() and sbrk() functions are legacy interfaces from before the
advent of modern virtual memory management.
之後 POSIX.1-2001 也把 brk() 跟 sbrk() 移除了,所以我說我知道的有點老。
後來我的志向不是做 OS,所以也沒有再重新 trace 相關細節過了。
總之這是個相當古老的東西,從 Version 7 AT&T UNIX 時代開始一路繼承下來的。
現在的做法我不知道,等專攻 OS 的進來補充。
推
08/29 23:40, , 7F
08/29 23:40, 7F
→
08/29 23:42, , 8F
08/29 23:42, 8F
→
08/29 23:43, , 9F
08/29 23:43, 9F
推
08/29 23:45, , 10F
08/29 23:45, 10F
推
08/30 00:21, , 11F
08/30 00:21, 11F
→
08/30 00:22, , 12F
08/30 00:22, 12F
以前常見的一種實作就是把 page table 起始位址存在 PTBR 這個暫存器,
所以會隨著 context switch 一起被儲存和恢復,因此自然會選到正確的那張。
這個技巧應該已經老到寫進課本蠻久了,你應該會有印象才對。
※ 編輯: tinlans (220.132.55.117), 08/30/2016 01:37:45
推
08/30 01:09, , 13F
08/30 01:09, 13F
→
08/30 01:11, , 14F
08/30 01:11, 14F
→
08/30 01:11, , 15F
08/30 01:11, 15F
推
08/30 01:16, , 16F
08/30 01:16, 16F
→
08/30 01:17, , 17F
08/30 01:17, 17F
如果你有把原 po 說的那本書看完,你應該會知道 stack 和 heap 中間還有夾其它東西。
簡單 Google 一下的話可以發現像這樣的圖:
http://static.duartes.org/img/blogPosts/linuxFlexibleAddressSpaceLayout.png

如果你兩邊都能在 runtime 往中間無限推,那麼做 OS 的人應該會很頭痛。
還好大部分的 programmer 都被教育成不要濫用 stack 空間,所以沒什麼大問題。
實際上一般應用程式,包括 MySQL 和 nginx 在內,stack 空間的需求都比你想像得小。
→
08/30 02:03, , 18F
08/30 02:03, 18F
→
08/30 02:03, , 19F
08/30 02:03, 19F
→
08/30 02:06, , 20F
08/30 02:06, 20F
※ 編輯: tinlans (220.132.55.117), 08/30/2016 02:12:46
→
08/30 02:09, , 21F
08/30 02:09, 21F
→
08/30 02:10, , 22F
08/30 02:10, 22F
runtime 增加的方法我就真的沒聽過了,時代真進步。是哪個 system call?
→
08/30 02:11, , 23F
08/30 02:11, 23F
→
08/30 02:12, , 24F
08/30 02:12, 24F
推
08/30 02:13, , 25F
08/30 02:13, 25F
→
08/30 02:13, , 26F
08/30 02:13, 26F
→
08/30 02:14, , 27F
08/30 02:14, 27F
※ 編輯: tinlans (220.132.55.117), 08/30/2016 02:15:54
推
08/30 02:17, , 28F
08/30 02:17, 28F
→
08/30 02:19, , 29F
08/30 02:19, 29F
→
08/30 02:19, , 30F
08/30 02:19, 30F
確實是它,雖然我一直都知道這個 system call 的存在,
不過一直以為只有在 execve() 被呼叫的當下會去看而已。
剛才查了一下,至少確定它在 BSD 家族可以在 runtime 調整 stack size。
因為長期在做 compiler 這塊,記憶漸漸被竄改成在 linker 指定是最後的機會 XD
→
08/30 02:24, , 31F
08/30 02:24, 31F
※ 編輯: tinlans (220.132.55.117), 08/30/2016 03:06:31
→
08/30 15:21, , 32F
08/30 15:21, 32F
→
08/30 15:21, , 33F
08/30 15:21, 33F
推
08/30 22:38, , 34F
08/30 22:38, 34F
推
08/31 18:19, , 35F
08/31 18:19, 35F
→
08/31 18:20, , 36F
08/31 18:20, 36F
討論串 (同標題文章)
本文引述了以下文章的的內容:
完整討論串 (本文為第 3 之 3 篇):