看板 C_and_CPP 關於我們 聯絡資訊
※ 引述《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
tjjh89017: 你沒有假設ASLR disable的情況 08/29 16:53
tjjh89017: 不能說「stack 起始位址都是一模一樣的」 08/29 16:53
tinlans: 確實現在的系統 ASLR 預設都打開了,但會把他的問題更 08/29 21:14
tinlans: 複雜化。不過還是感謝補充 XD 08/29 21:14
wtchen: 請問個問題,32bit一個process就4GB,64bit應該就unlimit 08/29 23:15
wtchen: 那系統要怎麼判斷有無out-of-memory? 08/29 23:16
我知道的部分是有點老了,而且是 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 的進來補充。
suhorng: 4GB 是 memory address space, 要用記憶體要配置才有 08/29 23:40
suhorng: 作業系統管理記憶體的分配跟 mapping, 會知道有沒有 OOM 08/29 23:42
ah7675: address space跟使用多少是兩回事啊啊啊 08/29 23:43
lsc36: 指標有32/64bit這麼長可是還是要跟OS拿page來用啊 08/29 23:45
kyuudonut: 謝謝前輩回答,所以kernel在切換process的時候,會再 08/30 00:21
kyuudonut: 依另外依各自的page table做映射的意思嗎? 08/30 00:22
以前常見的一種實作就是把 page table 起始位址存在 PTBR 這個暫存器, 所以會隨著 context switch 一起被儲存和恢復,因此自然會選到正確的那張。 這個技巧應該已經老到寫進課本蠻久了,你應該會有印象才對。 ※ 編輯: tinlans (220.132.55.117), 08/30/2016 01:37:45
wtchen: 那請問一個process裡的不同thread的stack要怎麼劃? 08/30 01:09
wtchen: 據我所知Linux預設的stack size limit是8MiB 08/30 01:11
wtchen: 遠小於user space的3GB... 08/30 01:11
wtchen: 其實我很不懂heap是往下延伸stack往上直到兩者相撞的話 08/30 01:16
wtchen: 為啥heap還是可以無限增加(看OS支援大小)而stack不行 08/30 01:17
如果你有把原 po 說的那本書看完,你應該會知道 stack 和 heap 中間還有夾其它東西。 簡單 Google 一下的話可以發現像這樣的圖: http://static.duartes.org/img/blogPosts/linuxFlexibleAddressSpaceLayout.png
如果你兩邊都能在 runtime 往中間無限推,那麼做 OS 的人應該會很頭痛。 還好大部分的 programmer 都被教育成不要濫用 stack 空間,所以沒什麼大問題。 實際上一般應用程式,包括 MySQL 和 nginx 在內,stack 空間的需求都比你想像得小。
PkmX: linux的話thread的stack是userspace自己allocate然後pass給 08/30 02:03
PkmX: clone(2) 08/30 02:03
PkmX: 8MB是預設的softlimit 你爽的話也可以ulimit -s去加大它 08/30 02:06
※ 編輯: tinlans (220.132.55.117), 08/30/2016 02:12:46
PkmX: 其實我很討厭往上/下長的說法 說往0或無限大長不是很好嗎XD 08/30 02:09
kdjf: stack也可以無限加,只是OS申請 08/30 02:10
runtime 增加的方法我就真的沒聽過了,時代真進步。是哪個 system call?
kdjf: 要先跟OS申請 08/30 02:11
kdjf: heap要用brk跟系統要空間一樣 08/30 02:12
wtchen: 感謝說明,受教了 08/30 02:13
kdjf: 只是習慣上把已知一定連續又可預測生命的資料放在自然連續的 08/30 02:13
kdjf: stack裡方便又快 08/30 02:14
※ 編輯: tinlans (220.132.55.117), 08/30/2016 02:15:54
kdjf: 剛剛google到setrlimit,可能是他吧 08/30 02:17
kdjf: 不過stack叫做stack&他的用法可能是古老的hardware stack 08/30 02:19
kdjf: 時留下來的? 08/30 02:19
確實是它,雖然我一直都知道這個 system call 的存在, 不過一直以為只有在 execve() 被呼叫的當下會去看而已。 剛才查了一下,至少確定它在 BSD 家族可以在 runtime 調整 stack size。 因為長期在做 compiler 這塊,記憶漸漸被竄改成在 linker 指定是最後的機會 XD
tjjh89017: 是說,64bit還有實體定址的問題,不是真的一定有2^64 08/30 02:24
※ 編輯: tinlans (220.132.55.117), 08/30/2016 03:06:31
kyuudonut: 謝謝前輩指點! 難怪每次看到memory的記憶體分配圖 08/30 15:21
kyuudonut: 有些都會稱為 process memory 08/30 15:21
CaptainH: 推 08/30 22:38
askacis: linux下setrlimit()也是可以用來調Stack size 08/31 18:19
askacis: pthread_attr_setstacksize()可以拿來調整thread 08/31 18:20