2011-07-01 68 views
3

讓我開始說我已經閱讀this tutorial並已閱讀this question。我的問題是:C++一些Stack問題

  1. 堆棧有多大?處理器/架構/編譯器 是否依賴於 ?

  2. 有沒有辦法知道 多少內存究竟是如何提供給我 函數/類棧,又有多少是目前正在使用,以 避免溢出 ?

  3. 利用現代的編譯器(比如gcc的4.5)現代計算機上 (比如說6 GB RAM), 做我需要擔心的堆棧溢出 或者是它的 過去的事情?

  4. 實際堆棧內存 物理上在RAM或CPU緩存上?

  5. 堆棧內存快多少錢 訪問和讀堆比較堆 訪問和讀?我意識到 次是PC特定的,所以一個比例是 就夠了。

  6. 我讀過不建議 在 堆棧上分配大變量/對象。多大太大?對於win32中的線程,This question here給出了1MB的回答 。如何 關於Linux amd64中的一個線程?

我很抱歉,如果這些問題已被問及已回答,歡迎任何鏈接!

+4

我認爲這會更好地分解成幾個更有針對性的問題。 –

+0

它涵蓋的範圍太廣泛,只有一個答案,實際上,它是10個完全不同的問題。 – littleadv

+0

我應該怎麼做?拿出一些問題,並在另一個線程中詢問他們? –

回答

8
  1. 是的,堆棧大小的限制各不相同,但如果你在意你可能做錯了什麼。
  2. 通常情況下,您無法獲取有關您的程序有多少內存可用的信息。即使你能獲得這樣的信息,在你使用它之前通常也是陳舊的。
  3. 如果你跨線程共享數據訪問,那麼你通常需要序列化訪問,除非它們是嚴格只讀的。
  4. 您可以將堆棧分配對象的地址傳遞給另一個線程,在這種情況下,您(再次)必須序列化,除非該訪問是嚴格只讀的。
  5. 即使在擁有大量內存的現代機器上,您當然也可以溢出堆棧。堆棧通常僅限於整個內存的一小部分(例如4MB)。
  6. 堆棧被分配爲系統內存,但通常足夠使用,以至於在任何給定時間,至少頂層頁面或兩層頁面通常都會在緩存中。
  7. 作爲堆棧與堆的一部分不會直接影響訪問速度 - 兩者通常駐留在相同的存儲器芯片中,並且通常甚至在同一存儲器芯片中的不同地址處。主要區別在於堆棧通常是連續的並且大量使用,前幾頁幾乎總是在緩存中。基於堆的內存通常是分段的,因此需要更多的數據不在緩存中。
  8. 對於您應該在堆棧中分配的對象的最大大小,幾乎沒有任何變化。即使堆棧可以大於,也沒有理由在那裏分配巨大的對象。
  9. 在C++中避免內存泄漏的主要方法是RAII(也稱爲SBRM,基於堆棧的資源管理)。
  10. 智能指針本身是一個很大的主題,Boost提供了幾種類型。根據我的經驗,集合可以產生更大的差異,但基本思想在很大程度上都是相同的:減輕程序員在特定對象可以被使用或應該被釋放時跟蹤每一種情況。
+0

我有最後一個問題給你,類成員變量在哪裏默認分配給? (假設我沒有指定它們在堆棧或堆上)。謝謝你回答我的問題! –

+1

@Alex:靜態分配靜態成員(大驚喜)。否則,這取決於你如何分配對象,而不是你如何定義類。 –

+1

@Alex成員存儲在任何存儲對象的地方。如果你有'class Foo {Bar b; }'然後在堆棧上放一個'Foo'會在堆棧上放一個'Bar'。 –

2

1-2:在某些嵌入式CPU上,堆棧可能被限制爲幾個千字節;在某些機器上它可能會擴展到千兆字節。沒有平臺無關的方法來知道堆棧有多大,在某種程度上,因爲有些平臺在達到極限時能夠擴展堆棧;這種手術的成功並不總是可以預先預測的。

3:在沒有鎖,互斥或其他此類設備的情況下,幾乎同時寫入或寫入一個線程中幾乎與另一線程中的讀取幾乎同時發生的影響在很大程度上是不可預知的。可以假定某些事情(例如,如果一個線程讀取堆存儲的'int',而另一個線程將其從4更改爲5,則第一個線程可能會看到4或可能看到5;在大多數平臺上,它將得到保證不看27)。

4:某些平臺在線程之間共享堆棧地址空間;別人不會。儘管如此,將指針傳遞給堆棧上的東西通常是一個壞主意,因爲接收指針的外部線程無法確保目標處於作用域中,並且不會超出作用域。

5:一般來說,不需要擔心寫入的任何例程中的堆棧空間,以限制遞歸到合理的級別。然而,人們需要擔心有缺陷的數據結構造成無限遞歸的可能性,無論這些數據可能有多大都會消除堆棧。人們還應該注意可能導致惡劣的輸入,這會導致比預期更大的堆棧深度。例如,使用遞歸下降解析器的編譯器可能會嗆入一個文件中,該文件包含10億次重複序列「1+(」。即使機器有一堆棧空間,如果每個嵌套子表達式使用64個字節上面提到的三個gig文件可能會導致它死亡

6:堆棧通常存儲在RAM和/或緩存中;最近訪問的部分通常在緩存中,而最近訪問的部分部件將在主內存中,代碼,堆和靜態存儲區也是如此。

7:這是非常依賴系統的;一般來說,在堆上「找到」某些東西需要花費很多時間在堆棧中訪問一些東西,但在許多情況下對同一個人的不同部分進行多次訪問ap對象可以像訪問堆棧對象一樣快。

3

1.堆棧多大?它是處理器/架構/編譯器依賴嗎?

堆棧的大小由存儲器的量的平​​臺的存儲器由操作系統分配給進程的量上的限制。

2.是否有一種方法可以確切知道我的函數/類堆棧有多少內存可用,以及當前使用了多少內存以避免溢出?

沒有用於確定可用內存量的C或C++工具。對此可能有特定於平臺的功能。一般來說,大多數程序試圖分配內存,然後爲分配失敗提供解決方案。

3.在現代計算機上使用現代編譯器(比如說gcc 4.5)(例如6 GB RAM),我需要擔心堆棧溢出還是過去的事情?

堆棧溢出可能發生取決於程序的設計。無論內存大小如何,遞歸都是耗盡堆棧的一個很好的例子。

4.實際的堆棧內存物理地位於RAM或CPU緩存上嗎?

平臺依賴。一些CPU可以用堆棧中的局部變量加載它們的緩存。關於此主題的各種場景。未在語言規範中定義。

5.與堆訪問和讀取相比,堆棧內存訪問和讀取速度快多快?
我意識到時間是PC特定的,所以一個比例就足夠了。

通常速度沒有差別。取決於平臺如何組織其物理內存以及如何佈置可執行文件的內存。堆或棧可以駐留在串行存取存儲器芯片(一種緩慢的方法)或甚至在閃存芯片上。未在語言規範中指定。

6.我讀過了,建議在堆棧上分配大的變量/對象是不可取的。多大太大?這裏的問題給出了一個1MB的線程在win32中的答案。如何在Linux amd64中的線程?

最好的建議是根據需要分配本地小變量(也可以通過堆棧)。巨大的項目是從動態存儲器(a.k.a.堆)或某種全局(靜態本地函數或本地到翻譯單元甚至是全局變量)分配的。如果大小在編譯時已知,則使用全局類型分配。在運行期間大小可能會更改時使用動態內存。

該堆棧還包含有關功能地址的信息。這是不能在本地分配大量對象的一個​​主要原因。一些編譯器對堆棧的限制比對堆或全局變量的限制更小。前提是嵌套函數調用比大數據數組或緩衝區需要更少的內存。

請記住,切換線程或任務時,操作系統需要在某處保存狀態。操作系統可能有不同的規則來保存堆棧內存與其他類型的內存。