作者zxvc (眾生都是未來佛)
看板C_and_CPP
標題Re: [問題] stack v.s. heap sizes
時間Mon Aug 30 11:47:05 2010
我最近剛好又須要探討這個問題。
其實我一直對max stack size遠小於max heap size感到疑惑。
沒道理,automatic variables速度比dynamic variables快,
compiler要限制max stack size遠小於max heap size。
雖然之前Ebergies大有給個理由,但我一直覺得怪怪的,
在最後文章會有我的論點。
所以我又上google去找原因。
我發現真的有人說[1]"能用stack就用stack。不能用stack,才用heap。"
"In C++ use stack objects where you can, use heap objects when you have
to," said Peter van Merkerk.
"To summarize, use automatic storage whenever you can and dynamic
storage only when you must," said Tom.
但這並沒有解決我所有疑惑:為什麼max stack size那麼小?
max stack size那麼小,很容易就用光了。
後來我就去查Visual C++ max stack size是多少,但MSDN沒說多少,只說有上限[2]。
後來我只好自己去試。我發現我在Visual C++ 2010 Express的/stack設定
加了好多位數,都可以compile/link。
加到後來我驚覺一件事:
Visucal C++早就可以叫很大的stack size。 後來我換成Visual C++ 2008 Express SP1,也是可以叫很大的stack size,
不是一般謠傳的16 MB[3]、32MB那麼小。 我的OS是Win 7 32-bit。
Visual C++ 2008的total automatic space上限是2GB,超過2GB會compile失敗。
我目前試出stack size可以到1.9G:
http://pic.pimg.tw/zxvc/c4855512304ed246d7142a8fe037d428.png?v=1283134381 http://pic.pimg.tw/zxvc/48f26a14e566dbd9f3d401b96e104879.png?v=1283134381 不過上圖一的那個"Memory (Priva..."其實只算physical memory的使用量,
要叫出phy+virtual memory,可以View/Select Columns.../Memory - Commit Size
※ 引述《zxvc (修行)》之銘言:
: 標題: [問題] stack v.s. heap sizes
: 時間: Sat Sep 12 20:14:48 2009
:
: 在Windows上stack最大可以設到32MB,
: heap卻可以設定到2GB。
:
: 請問為何這兩個限制大小差那麼多?
: 靜態變數(在stack)不是效能比較好嗎!?
: 為什麼需要配置大量空間不建議配置在stack?
:
: --
: ※ 發信站: 批踢踢實業坊(ptt.cc)
: ◆ From: 140.115.221.79
: → suhorng:靜態變數!? 09/12 20:54
: → zxvc:應該說"靜態記憶體配置的變數"。 09/12 21:08
: 推 bobhsiao:stack是給local var用的, 通常幾十KB就夠了 09/12 22:12
: → bobhsiao:heap是給malloc/new用的, 使用量視AP而定 09/12 22:13
: 推 final01:heap可動態釋放!不過stack效能較好到是事實巴 09/12 23:06
: 推 Ebergies:這是邏輯上的思考, 通常 stack 是用來存取 function 內 09/12 23:15
: → Ebergies:的變數, 若 function 內的 local var 過大, 那麼這個 09/12 23:15
: → Ebergies:function 勢必不夠靈活, 光 recursive 沒幾次再大的 09/12 23:16
: → Ebergies:stack 也不夠用, 而這類超大空間的配置就使用上也大多 09/12 23:17
: → Ebergies:只需要配置很少的次數, 因此放在 heap 是合理且好的作法 09/12 23:17
不好意思,這樣有個假設,
就是所有漂亮的程式碼都不會是"遞迴且有很大的local variables"。
請問這能證出來嗎!?如果不能,這種coding style未必不好。
就算可能某些遞迴情形下,這些variables真的太大了,
難道"dynamic variables"就能解決這問題嗎?
如果max stack size可以跟max heap size一樣大(事實上stack真得可以很大),
heap的1MB會等於stack的1GB嗎?
既然不會,沒道理"遞迴且有很大的variables,用stack不夠,用heap會夠!?"
又stack不一定是要用在遞迴,
比如我想在main function用到一個很大的local variable。
所以我認為heap的好處不是在因為function不能遞迴很多次,
是在於它能動態產生、釋放記憶體。
: → zxvc:謝謝樓上。 09/14 20:16
References:
[1]
http://www.velocityreviews.com/forums/t278261-stack-vs-heap.html [2]
http://msdn.microsoft.com/en-us/library/tdkhxaks(VS.71).aspx [3]
http://bluecat.csie.net/2009/10/28/3924/ --
信佛的人要知道:佛絕不會說謊。但請把握時光。
法滅盡經:
http://www.cbeta.org/result/normal/T12/0396_001.htm 共勉之。
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.115.73.148
※ 編輯: zxvc 來自: 140.115.73.148 (08/30 12:39)
→ tinlans:stack 是靜態預先配置出來的記憶體空間,配都配了, 08/30 12:59
→ tinlans:能用當然就要盡量用。如果你把 stack 設定成 1G, 08/30 12:59
→ tinlans:你的程式一啟動,記憶體就吃掉 1G 了。 08/30 13:00
→ tinlans:雖然一般計概是告訴你 call 進 function 會 push 一個 08/30 13:02
→ tinlans:stack frame,但這不代表空間是在 push 的時候才配置。 08/30 13:02
→ tinlans:那個 push 的動作只是把 stack pointer 跳一下,當然相對 08/30 13:02
→ tinlans:來說 pop 也只是向下跳。在沒有使用 alloca() 的前提下, 08/30 13:02
→ tinlans:每個 function 的 stack frame size 是被 compiler 靜態 08/30 13:03
→ tinlans:預先計算好的。所以 stack 上的各種操作只是單純的 08/30 13:03
→ tinlans:算術運算。heap 上就真的有配置、釋放的動作,速度有差。 08/30 13:04
→ tinlans:如果我是你的客戶,開個小程式就要吃 1.9G 的記憶體, 08/30 13:04
→ tinlans:我一定打電話去你公司客服狗幹。 08/30 13:04
→ tinlans:heap 的狀況不一樣,因為它的位置在後面。lib 的 malloc() 08/30 13:08
→ tinlans:實作發現 heap 容量不足時,才會用系統呼叫跟 OS 要記憶體 08/30 13:09
→ tinlans:。所以幾乎是用多少配多少 (當然還是會預留一些空間), 08/30 13:10
→ tinlans:這跟 stack 一開始就配下去的狀況完全不同。 08/30 13:10
→ tinlans:而且在 user space 只有 2G 的虛擬記憶體模型下,stack 08/30 13:14
→ tinlans:就佔了那麼多,相對的你的 code / data / heap 可用空間就 08/30 13:14
→ tinlans:受到限制。malloc() 也許常常傳回 NULL。 08/30 13:15
推 loveflames:heap可以有很多個,stack通常只有一個 08/30 13:24
→ zxvc:t大,三樓的確是stack的一個缺點,這應該才是stack有時不能太 08/30 13:27
→ zxvc:大的原因吧。 08/30 13:27
→ tinlans:上面有個地方沒講清楚,heap 的位置被配在後面並不代表 08/30 13:31
→ tinlans:是在 stack 後面。stack 一般是被 OS 配置在最高位址區。 08/30 13:32
→ tinlans:然後開 thread 的時候,會出現第二個 stack。 08/30 13:33
→ zxvc:如果為了追求速度,且寫程式只是為了特定目的(如作研究),這 08/30 13:34
→ zxvc:時是可以多利用stack的好處的。 08/30 13:35
→ zxvc:l大,那會造成什麼問題? 08/30 13:36
→ tinlans:不一定啦,你可以在 heap 一次 allocate 超大的空間做成 08/30 13:38
→ tinlans:memory pool,這樣也能大幅節省配置/釋放的時間開銷。 08/30 13:38
→ zxvc:同意t大,"超大空間、很少次配置,用heap也不會太差",E大也 08/30 13:57
→ zxvc:有提到這一點。至於有沒有"超大空間,很多次配置"的這種應用 08/30 13:58
→ zxvc:就不清楚有沒有了。 08/30 13:59
推 loveflames:stack配置在最高位址區是linux/unix才這樣吧? 08/30 15:10
→ loveflames:windows放得很前面 08/30 15:11
→ tinlans:windows 就不清楚了,C 最初是拿來寫 UNIX,所以大部分書 08/30 15:14
→ tinlans:的例子都是舉 UNIX。加上 stack 跟 heap 有必要放在兩個 08/30 15:14
→ tinlans:相對的端點上,然後向中間生長。 08/30 15:15
→ tinlans:heap 可以往中間 grow,stack 會隨著 thread 數量往中間 08/30 15:16
→ tinlans:allocate。任一種做法都會壓縮到對方未來可配置的空間。 08/30 15:16
→ tinlans:反過來設計應該也沒什麼不好,重點是 heap 要有地方 grow 08/30 15:17
推 loveflames:windows的heap切成好幾個區塊,然後用一個heap table記 08/30 15:18
→ loveflames:錄其範圍,我不太喜歡這種作法 08/30 15:18
→ tinlans:之前看 exceptional C++ 有說 C++ 其實是用 free storage 08/30 15:19
→ tinlans:配置動態記憶體空間,不保證 free storage == C 的 heap。 08/30 15:20
→ tinlans:其它地方就比較少聽到這類說法,但從這點聽起來 heap 被 08/30 15:20
→ tinlans:分成多個區域似乎也還算合理。只是可能要考慮 fragment 08/30 15:21
→ tinlans:的問題。 08/30 15:21
→ tinlans:不過如果要一次 allocate 1.5G 的 array, 08/30 15:23
→ tinlans:我蠻好奇這樣切開來要怎麼 allocate。 08/30 15:23
→ zxvc:t大,我後來發現Windows並不是stack reserve size設多少 08/30 21:40
→ zxvc:physical mem就被吃多少。 08/30 21:40
→ zxvc:比如,設個很大的stack reserve size,然後完全沒宣告任何 08/30 21:42
→ zxvc:automatic variables,用Windows Task Manager看會發現沒有 08/30 21:43
→ zxvc:真的吃到那麼多記憶體。 08/30 21:43
→ zxvc:另外我這篇對virtual memory的部分有些誤解,大家先忽略那幾 08/30 21:45
→ zxvc:句話。 08/30 21:45
→ tinlans:process 是在 virtual address space 上工作的,所以當然 08/30 22:07
→ tinlans:不會在你沒使用到的時候就去佔到實體記憶體。 08/30 22:08
→ tinlans:但是這完全依賴 OS 的實作,如果很不幸的你偏偏就只用到那 08/30 22:09
→ tinlans:麼大的空間一次而已,實體空間就這樣被你佔下來。後續其它 08/30 22:09
→ tinlans:process 也要佔用實體記憶體時,swap out 就會拖慢速度。 08/30 22:10
→ tinlans:如果是在沒有虛擬記憶體的 real-time system,這樣搞就會 08/30 22:11
→ tinlans:直接往實體記憶體吃下去了。 08/30 22:11
→ tinlans:但是最大的問題還是在於,32-bit 系統上定址空間有限。 08/30 22:12
→ tinlans:你如果是 user/kernel = 2G/2G 的 model,stack 一吃就把 08/30 22:12
→ tinlans:user space 的 90% 吃光光,你 heap 的可用空間就會受限。 08/30 22:12
→ tinlans:另一個問題就在於你無法開 thread,因為開 thread 會由 OS 08/30 22:13
→ tinlans:配置第二個 stack 出來給新的 thread 用。 08/30 22:13
→ tinlans:如果你想讓 stack 變成跟 heap 一樣會動態增長, 08/30 22:17
→ tinlans:不是一開始就 allocate 好,那就得在每個 function call 08/30 22:18
→ tinlans:跟 return 的位置做一些 stack size 的檢查,然後決定 08/30 22:18
→ tinlans:是不是要跟 OS 要更多 stack 的空間,程式會又慢又肥。 08/30 22:19
推 VictorTom:推t大的說明:) 08/30 23:14
推 loveme00835:推 t 大熱心, 好久沒看到 v 大 XD 08/30 23:29
推 nowar100:我覺得這篇推文很有價值 等下看怎樣收進精華區 08/30 23:30