Re: [問題] memory stack 的問題

看板C_and_CPP作者 ( )時間9年前 (2016/08/29 13:36), 9年前編輯推噓10(10026)
留言36則, 11人參與, 最新討論串3/3 (看更多)
※ 引述《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
你沒有假設ASLR disable的情況
08/29 16:53, 1F

08/29 16:53, , 2F
不能說「stack 起始位址都是一模一樣的」
08/29 16:53, 2F

08/29 21:14, , 3F
確實現在的系統 ASLR 預設都打開了,但會把他的問題更
08/29 21:14, 3F

08/29 21:14, , 4F
複雜化。不過還是感謝補充 XD
08/29 21:14, 4F

08/29 23:15, , 5F
請問個問題,32bit一個process就4GB,64bit應該就unlimit
08/29 23:15, 5F

08/29 23:16, , 6F
那系統要怎麼判斷有無out-of-memory?
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
4GB 是 memory address space, 要用記憶體要配置才有
08/29 23:40, 7F

08/29 23:42, , 8F
作業系統管理記憶體的分配跟 mapping, 會知道有沒有 OOM
08/29 23:42, 8F

08/29 23:43, , 9F
address space跟使用多少是兩回事啊啊啊
08/29 23:43, 9F

08/29 23:45, , 10F
指標有32/64bit這麼長可是還是要跟OS拿page來用啊
08/29 23:45, 10F

08/30 00:21, , 11F
謝謝前輩回答,所以kernel在切換process的時候,會再
08/30 00:21, 11F

08/30 00:22, , 12F
依另外依各自的page table做映射的意思嗎?
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
那請問一個process裡的不同thread的stack要怎麼劃?
08/30 01:09, 13F

08/30 01:11, , 14F
據我所知Linux預設的stack size limit是8MiB
08/30 01:11, 14F

08/30 01:11, , 15F
遠小於user space的3GB...
08/30 01:11, 15F

08/30 01:16, , 16F
其實我很不懂heap是往下延伸stack往上直到兩者相撞的話
08/30 01:16, 16F

08/30 01:17, , 17F
為啥heap還是可以無限增加(看OS支援大小)而stack不行
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
linux的話thread的stack是userspace自己allocate然後pass給
08/30 02:03, 18F

08/30 02:03, , 19F
clone(2)
08/30 02:03, 19F

08/30 02:06, , 20F
8MB是預設的softlimit 你爽的話也可以ulimit -s去加大它
08/30 02:06, 20F
※ 編輯: tinlans (220.132.55.117), 08/30/2016 02:12:46

08/30 02:09, , 21F
其實我很討厭往上/下長的說法 說往0或無限大長不是很好嗎XD
08/30 02:09, 21F

08/30 02:10, , 22F
stack也可以無限加,只是OS申請
08/30 02:10, 22F
runtime 增加的方法我就真的沒聽過了,時代真進步。是哪個 system call?

08/30 02:11, , 23F
要先跟OS申請
08/30 02:11, 23F

08/30 02:12, , 24F
heap要用brk跟系統要空間一樣
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
stack裡方便又快
08/30 02:14, 27F
※ 編輯: tinlans (220.132.55.117), 08/30/2016 02:15:54

08/30 02:17, , 28F
剛剛google到setrlimit,可能是他吧
08/30 02:17, 28F

08/30 02:19, , 29F
不過stack叫做stack&他的用法可能是古老的hardware stack
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
是說,64bit還有實體定址的問題,不是真的一定有2^64
08/30 02:24, 31F
※ 編輯: tinlans (220.132.55.117), 08/30/2016 03:06:31

08/30 15:21, , 32F
謝謝前輩指點! 難怪每次看到memory的記憶體分配圖
08/30 15:21, 32F

08/30 15:21, , 33F
有些都會稱為 process memory
08/30 15:21, 33F

08/30 22:38, , 34F
08/30 22:38, 34F

08/31 18:19, , 35F
linux下setrlimit()也是可以用來調Stack size
08/31 18:19, 35F

08/31 18:20, , 36F
pthread_attr_setstacksize()可以拿來調整thread
08/31 18:20, 36F
文章代碼(AID): #1NmydpAZ (C_and_CPP)
文章代碼(AID): #1NmydpAZ (C_and_CPP)