2011-03-11 21 views
12

皮質M3處理器啓動文件允許用戶指定的RAM專用於棧和堆的量。對於一個C++代碼庫,是否有一個通用的經驗法則或者一些更明確的方式來確定堆棧和堆大小的值?例如,你會計算唯一對象的數量和大小,還是使用編譯的代碼大小?如何確定用於ARM皮質適當堆和棧大小,用C++

+0

這是比特定CPU架構更特定的編譯器和運行時庫。但最重要的是,這是確定內存使用情況的代碼。使用MMU或數據斷點捕捉堆棧溢出。 – 2011-03-12 00:10:24

+0

可能的重複[如何確定最大堆棧使用?](http://stackoverflow.com/questions/389219/how-to-determine-maximum-stack-usage) – 2011-03-12 10:53:03

+0

@本:Cortex-M3沒有MMU,但它具有數據訪問硬件斷點支持,這可能有助於在測試期間提供幫助,但不能用於部署。 – Clifford 2011-03-12 21:54:30

回答

14

皮質M3處理器啓動文件 允許指定的 RAM專用於堆疊中的量和 堆。

這不是在Cortex-M3的功能,而是由你的開發工具鏈提供的啓動代碼。這是M3的Keil ARM-MDK默認啓動文件的工作方式。它有點不尋常;更常見的是你會指定一個堆棧的大小,堆棧和鏈接器分配的靜態內存之後的剩餘內存將成爲堆;這可以說是更好,因爲你不會結束一堆無法使用的記憶。你可以修改它並使用另一種方案,但你需要知道你在做什麼。

如果您使用Keil ARM-MDK的,鏈接器選項--info = stack和--callgraph將信息添加到幫助堆棧需求分析的映射文件中。這些和其他技術被描述爲here

如果您使用的是RTOS或者多任務處理內核,每個任務都會有它自己的堆棧。操作系統可能提供堆棧分析工具,Keil的RTX內核查看器顯示當前堆棧使用情況,但不顯示峯值堆棧使用情況(所以大多數情況下是無用的,並且只能用於默認堆棧長度的任務)。

如果您必須自己實現堆棧檢查工具,常規方法是用已知值填充堆棧,並從高地址開始檢查該值,直到找到第一個不是填充字節的值,這將給出堆疊的高潮標記。您可以實現代碼來執行此操作,也可以手動從調試器中填充內存,然後在調試器內存窗口中監視堆棧使用情況。

堆需求將依賴於你的代碼的運行時行爲;你必須自己分析一下,但是在ARM/Keil Realview中,當C++的new引發異常時,將調用MemManage異常處理程序;我不知道如果malloc()這樣做或簡單地返回NULL。您可以在異常處理程序中放置斷點,或修改處理程序以發出錯誤消息來檢測測試期間的堆耗盡情況。還有一個__heapstats()函數可用於輸出堆信息。它有一個有些繁瑣的界面,我把它包這樣的:

void heapinfo() 
{ 
typedef int (*__heapprt)(void *, char const *, ...); 
    __heapstats((__heapprt)std::fprintf, stdout) ; 
} 
3

編譯後的代碼大小將不利於爲代碼在棧也不是堆運行。 Cortex-M3器件通常在具有內置閃存和相對較少的RAM的微控制器上實現。在此配置中,代碼通常將從Flash運行。

堆用於動態存儲器分配。計算唯一對象的數量將會給你一個粗略的估計,但你也必須考慮使用動態內存分配(使用在C new關鍵字++)的任何其他元素。一般來說,嵌入式系統中避免動態內存分配的原因是堆大小難以管理。

堆棧將用於變量傳遞,局部變量和上下文中的異常處理例程節約。除非你是代碼分配一大塊本地內存或一個大對象,否則一般很難理解堆棧的使用情況。一種可能有用的技術是分配堆棧中的所有可用RAM。用已知模式填充堆棧(0x00或0xff不是最佳選擇,因爲這些值經常發生),運行系統一段時間,然後檢查堆棧以查看使用了多少。誠然,這不是一個非常精確或科學的方法,但在許多情況下仍然有用。

1

IAR編譯器的最新版本具有一項功能,可根據代碼的靜態分析(假設您沒有任何遞歸)來確定需要的堆棧大小。

如果你沒有確切的數字,一般的做法是儘可能大,然後當你開始用盡內存時,開始修剪堆棧直到你的程序崩潰,因爲堆棧過流。我希望這是一個笑話,但這是通常的做法。

+0

事實上,這確實是大多數堆疊尺寸確定的方式,這對我們的行業來說是尷尬的! – odinthenerd 2015-05-12 11:25:34

0

減少到崩潰是一種快速臨時方式。您也可以使用已知的值填充堆棧,例如0xCCCC,然後通過掃描0xCCCC來監視最大堆棧使用情況。 這是不完美的,但比尋找崩潰要好得多。

原理是,減少堆棧大小並不能保證堆棧溢出會產生「可見」的東西。