2013-06-22 53 views
10

我正在構建一個小型軟件引擎,並且我希望大量使用棧來快速迭代大量集合。但是後來我想到這可能是一個壞主意,因爲堆棧不像堆一樣大。但是我被這個棧的速度所吸引,並且缺乏動態分配編碼實踐。是否可以確定堆棧上有多少空間可用?

有沒有辦法找出我可以在特定平臺上推送堆棧多遠?我主要關注移動設備,但這個問題可能出現在任何平臺上。

+0

不是重複的,但看看http://stackoverflow.com/q/1756285/1729885 –

+0

所以你想動態地(即在運行時)確定堆棧大小? – ComFreek

+0

我不認爲有任何一般的解決方案。堆棧大小可以在不同的線程之間有所不同 –

回答

7

在* nix,使用getrlimit

RLIMIT_STACK 
      The maximum size of the process stack, in bytes. Upon 
      reaching this limit, a SIGSEGV signal is generated. To handle 
      this signal, a process must employ an alternate signal stack 
      (sigaltstack(2)). 

在Windows上,使用VirtualQuery

對於第一個電話,在堆棧上的任何值的地址,把它傳遞給 得到基地地址和大小(以字節爲單位)提交的堆棧空間。 在堆棧向下增長的x86計算機上,再次從基地址和VirtualQuery中減去 的大小:這將爲您提供爲堆棧保留的空間大小 (假設您不是 正好在堆棧的極限上大小在當時)。總結這兩個 自然會給你總的堆棧大小。

由於堆棧大小在邏輯上屬於實施和主機系統,因此沒有獨立於平臺的方法 - 在嵌入式小型SOC上,分配的資源少於在128GB RAM服務器上分配的資源。但是,您可以通過特定於API的調用來影響所有操作系統上特定線程的堆棧大小。

1

從語言中沒有標準的方法。我甚至沒有意識到可以查詢的文檔擴展名。

但是有些編譯器可以選擇設置堆棧大小。平臺可以指定它在啓動進程時的功能,和/或提供設置新線程的堆棧大小的方法,甚至可以操縱現有的線程。

對於小平臺,通常知道整個內存大小,一端有所有的數據段,一個是堆大小的舞臺(可能是0),其餘的是棧,接近另一端。

2

在標準的C++中,絕對不是。以便攜的方式,可能不是。有時候在特定的操作系統中。如果沒有別的,你可以打開你自己的可執行文件大小並檢查可執行文件的頭文件來查看它的大小。 [下一個問題當然是「在這段代碼之前使用了多少堆棧」 - 這可能很難確定)。

如果您在單獨的線程中運行代碼,許多(低級別)線程接口允許您指定堆棧(或堆棧大小),例如Posix線程pthread_set_stacksize或MS _beginthread。再次,你不知道在達到實際的線程代碼之前已經佔用了多少空間 - 但它可能不是一個巨大的數量。當然,在嵌入式系統(例如手機)中,堆棧大小通常非常小,4K,12K或64KB非常正常 - 有時甚至比有些系統小得多。

另一個潛在的問題是,你不能真正知道在堆棧中實際使用了多少空間 - 你可以在編譯系統中測量這個事實,當然,如果你有一個堆棧本地數組int array[25];,我們可以知道它佔用至少25 * sizeof(int) - 但有可能是填充,編譯器保存在棧上的寄存器,等等,等等

編輯,事後的想法: 我還沒有真正看到有那麼多好處兩個代碼路徑:

if (enough_stack_space_for_something) 
     use_stack_based_algorithm(); 
else 
     use_heap_based_algorithm(); 

這會增加相當數量的額外開銷和更多的代碼在嵌入式/移動系統中通常不是一個好計劃。編輯2:另外,如果分配內存是運行時的主要部分,也許看看爲什麼,例如塊的對象創建會有所幫助?

5

可能的便攜式解決方案是自己編寫一個分配器。
您不必使用進程堆棧,只需在堆中模擬即可。
在開始時分配大量內存,並在其上寫入堆棧分配器以在分配時使用它。
有關如何在C++中實現它的信息,Google的「分配器要求」。

我不確定'Stack Allocator'這個術語是否是規範的,但我的意思是說你必須把堆棧放在像分配或釋放的地方那樣的限制上。
既然你說你的算法適合這種模式,我認爲這很容易。

2

爲了擴大已經給出的答案,爲什麼沒有可移植的方式來做到這一點,實際堆棧的整個概念不是標準的一部分。你可以編寫一個C或C++運行時,除了函數調用記錄(可能內部是一個鏈表或其他東西)之外,它不會使用棧。

堆棧是特定機器/操作系統/編譯器的實現細節。因此,任何訪問堆棧度量的技術都將針對機器/操作系統/編譯器。

雖然不是你的具體問題的實際答案(Niels覆蓋了這個很好),但作爲你的問題領域的建議:只是在堆中分配一大塊內存。除了方便之外,沒有任何理由說明「真正」的堆棧有什麼不同。高度遞歸(非尾遞歸)算法經常需要這樣做,以確保它們具有幾乎無限的「堆棧」。希望確保它們提供運行時錯誤/異常而不是崩潰主機應用程序的腳本語言也經常這樣做。爲了有效地處理事情,你可以實現一個「拆分堆棧」(就像std::deque會給你的),或者你可以確保預先分配一個足夠大的棧來滿足你的需求。

+0

除了方便以外,沒有任何理由可以說「真正」的堆棧有任何不同。但是經常提到堆棧比堆快,所以它肯定不僅僅是方便嗎? – johnbakers

+0

堆上的_Allocations_(使用'malloc'或'new'或類似的東西)比在堆棧上創建局部變量或使用類似'alloca'的東西慢。堆棧大多會自動避免碎片和緩存局部性問題,如果您天真但可能會因堆使用而受到影響,但如果您小心,這些問題不會成爲問題。一些體系結構具有用於實現堆棧的明確指令,例如, x86上的'push'和'pop',但在大多數算法中它們的優勢將極其微小。除非你有性能數字證明你需要,否則不要擔心。 –

相關問題