精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

堆棧和內存的基本知識

MATLAB ? 來源:MATLAB ? 2024-08-29 14:10 ? 次閱讀

本文主要聊聊關于堆棧的內容。包括堆棧和內存的基本知識。常見和堆棧相關的 bug,如棧溢出,內存泄漏,堆內存分配失敗等。后面介紹軟件中堆棧統計的重要性,以及如何使用工具工具軟件中堆棧使用的范圍,并給出在軟件開發中,如何降低堆棧問題,優化堆棧的一些實踐。

隨著代碼行數從幾千增長到百萬甚至更多,嵌入式軟件變得日益復雜,但總體目標依然是實現軟件的需求,達到穩健、正確且快速執行。快速執行需要以最優方式管理可用的 CPU 和內存資源,這對內存空間(尤其是 RAM)有限的嵌入式系統來說是一項挑戰。

為此,必須通過執行堆棧和堆分析對 RAM 的使用情況進行詳細了解。開發人員手動估計堆棧和堆負載是一項艱巨的任務,哪怕對于小程序來說也是這樣。如果估計不正確,則可能會導致堆棧溢出和一些未定義的行為。因此,常見的編碼規范要求強制執行內存分配使用最佳實踐來避免不必要的開銷。但是,堆棧仍是 RAM 的必要組成部分,需要得到優化利用。

堆棧和內存

先簡單聊聊內存,內存是計算機中重要的單元,而堆棧是內存中最重要的應用組成。

C 語言的內存分配

嵌入式系統中,內存通常被分為幾個主要區域,每個區域存儲不同類型的數據,這些區域在使用方式、性能以及目的上各不相同。

下面主要說說堆區和棧區

1. 堆區

堆區用于動態內存分配,程序運行時可以從堆區動態地分配和釋放內存。其管理通常由程序的內存管理子系統(如 C 語言的 malloc 和 free 函數)負責。堆的大小和使用效率直接影響程序的性能和穩定性。而內存管理子系統通常都是程序員主動調用申請和釋放的。堆區位于 RAM 中,因此其內容在斷電后會丟失。

2. 棧區

棧區主要用于存儲局部變量、函數參數和返回地址等。棧具有后進先出(LIFO)的特性,每當調用新的函數時,函數的局部變量和返回地址就會被壓入棧中,函數返回時這些數據又會被彈出。棧區的系統自動管理的。棧區雖然高效但空間有限,這也導致棧溢出成為嵌入式系統中常見的問題之一。

堆區(Heap Memory)和棧區(Stack Memory)有以下幾個主要的區別:

1. 管理方式:

棧是自動管理的,由編譯器控制。當函數調用時,棧幀(Stack Frame)被自動創建和銷毀。

堆是手動管理的,需要程序員使用特定的函數(如malloc、free在C中)來分配和釋放內存。

2. 分配和釋放速度:

棧的分配和釋放速度通常較快,因為它們是連續分配的,并且不需要復雜的內存管理。

堆的分配和釋放速度較慢。差距的時間主要用在操作系統查找空閑內存塊,并可能涉及將內存塊從非連續的區域移動到連續的區域。

3. 內存碎片:

棧內存是連續分配的,通常不會產生內存碎片。

堆內存是動態分配的,每次大小不同,這導致堆上分配內存不連續,從而出現內存的碎片化。這需要定期進行內存整理(Memory Compaction)來優化性能。

堆棧統計為什么如此重要?

從上面關于堆棧的知識,我們知道堆棧的大小是有限的,堆棧對于程序運行極為重要。

當可用堆棧小于代碼需求時,就會發生堆棧溢出。然而,當為系統配置的堆棧大于需求時,內存又會被浪費。開發人員必須持續一致地估計安全關鍵型應用中最差情形下的堆棧使用量,以防止軟件運行時發生 RAM 不足的情況。

在設計嵌入式系統時,合理規劃和管理內存區域對于確保系統的性能、穩定性和可靠性十分重要。開發者需要根據應用的具體需求和硬件資源,做出恰當的內存使用決策。合理分配堆棧大小,通過堆棧統計來優化堆棧使用,對于確保系統的可靠性和安全性至關重要。

內存管理不當,會導致內存泄露(堆泄露)。而內存泄漏可能會堆棧的不足,進而出現堆棧溢出,這些是編程中常見的錯誤之一,而且極其嚴重。對于常規的桌面級應用,這些錯誤發生會導致程序卡頓或重啟崩潰。而對于涉及生命安全和重大財產安全的關鍵應用系統和軟件,堆棧不足可能導致數據損壞,系統不穩定和崩潰,進而導致人員傷亡和財產損失。

典型的內存問題

Memory Leak (內存泄漏)

內存泄漏更準確的說法是,堆內存泄漏 (heap leak),是程序員在分配一段內存后,分配的內存未被釋放且無法再次訪問時發生。

#include 


void leakMemory() {
    int *leak = (int*)malloc(sizeof(int) * 100);
    // 漏掉了釋放操作
}


int main() {
    leakMemory();
    return 0;
}

例子中,指針 leak 作為局部變量,在退出 leakMemory 函數后,沒有釋放且找不到地址無法再次訪問。

Stack Leak (棧泄漏)

當程序中的局部變量大量消耗棧資源,而又沒有退出該函數,導致 stack 溢出,大量的溢出可能會導致棧的不足,從而發生 overflow 的情況。這種一般發生在遞歸函數或者函數中有大循環,其有定義局部變量,比如下面的代碼

void stackLeak(int n) {

char buffer[1024];

printf("Leaking stack memory %d,%p\n", n, (void *)buffer);

if(n>1)

stackLeak(n - 1);

}

int main() {

stackLeak(500);

return 0;

}


在 32G 內存的筆記本上,運行到 373 次就棧溢出了。


wKgaombQES2AFnb1AAEisWjn2dk976.png ?
wKgZombQETGAVjLYAAGCkdWqPOQ296.png

Buffer overflow(緩沖區溢出)

Buffer overflow(緩沖區溢出)是一種常見的安全漏洞,通常發生在當程序試圖向一個固定長度的緩沖區寫入過多數據時,一般發生在字符操作的時候。盡管緩沖區溢出通常與堆棧溢出有所區別——前者涉及對固定大小緩沖區的寫操作超出其邊界,后者是函數調用和局部變量使用過多堆棧空間——但在實踐中,緩沖區溢出經常導致堆棧上的數據被覆蓋,因此可以視為一種堆棧不足引發的問題。

以下是一個使用C語言的示例,展示了一個簡單的緩沖區溢出漏洞:

#include 
#include 


void vulnerableFunction(char *str) {
    char buffer[10];
    strcpy(buffer, str); // 不安全的拷貝,拷貝應該指定大小
    printf("Buffer content: %s
", buffer);
}


int main() {
    char largeData[] = "這是一個超長的字符串,遠遠超過了buffer的容量";
    vulnerableFunction(largeData);
    return 0;
}

在這個例子中,vulnerableFunction函數定義了一個長度為 10 的字符數組buffer作為緩沖區。然后,它使用strcpy函數將傳入的字符串str拷貝到buffer中。如果str的長度超過了buffer的容量(在這個例子中是 10 個字符),就會發生緩沖區溢出。strcpy不會檢查目標緩沖區的大小,所以它會繼續寫入數據,直到遇到源字符串的結束符\0。

這種溢出可能會覆蓋堆棧上的其他重要數據,比如其他局部變量、函數返回地址等,導致程序行為異常,甚至允許黑客執行任意代碼。

為了避免這種安全漏洞,應該使用更安全的函數,如strncpy,它允許指定目標緩沖區的最大長度,從而避免溢出:

strncpy(buffer, str, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '?'; // 確保字符串以 null 結束

這樣就可以顯著減少因緩沖區溢出導致的安全風險。

Stack Frame Corruption (棧幀破壞)

棧幀中是函數的局部變量和函數調用時候的相關開銷。當我們對局部變量進行錯誤的操作時候,可能會破壞棧幀,導致函數的返回地址或其他重要數據被覆蓋。舉例如下。 #include void corruptStackFrame() { int arr[1] = {0}; int b = 10; int c = 20; arr[1] = 0; // 故意寫入數組界限之外,可能覆蓋返回地址 arr[2] = 0; // 故意寫入數組界限之外,可能覆蓋返回地址 printf("b=%d c=%d ", b, c); } int main() { corruptStackFrame(); return 0; }

上面的例子中,有明顯的數組越界的問題。同時,由于該數組是局部變量,對數組外的數進行操作,可能會導致周邊的棧幀給改寫,從而導致系統崩潰。

wKgaombQEY2AcsZlAAIKCuS-CwU962.jpg

當然棧幀是否被改寫可能涉及很多系統的很多方面。這里不詳細討論。

Memory Allocation Failed

當請求的內存無法被分配時發生。當請求大量內存時,可能會因為內存不足或者沒有足夠的連續內存導致分配內存失敗。

#include 


int main() {
    //分配大量內存
    int *bigArray = (int*)malloc(sizeof(int) * 1000000000);
    if (bigArray == NULL) {
        printf("Memory allocation failed
") //內存分配失敗
    }
    free(bigArray);
    return 0;
}

其他內存管理方面的問題還包括重復分配內存,野指針問題等,都會直接或間接的導致可用堆棧的減少。

歷史上,許多著名的軟件漏洞,如 Heartbleed、Spectre 等,都與堆棧管理不當有關。通過對堆棧進行統計,我們可以提前發現潛在的安全隱患,避免類似問題的發生。

Heartbleed 漏洞是由于 OpenSSL 庫中的堆棧管理錯誤導致的。該漏洞允許攻擊者讀取內存中的敏感信息,甚至可以修改內存內容。通過對堆棧進行統計和分析,可以發現 OpenSSL 庫中的堆棧使用不當,從而避免 Heartbleed 漏洞的產生。

堆棧統計促進軟件開發和性能優化

堆棧統計不僅可以幫助開發者確定程序在運行時堆棧的使用情況,還可以指導開發者進行性能優化。通過準確的堆棧使用數據,開發者可以合理分配堆棧大小,既避免了堆棧溢出的風險,也確保了系統資源的高效利用。

性能瓶頸定位:堆棧統計可以幫助開發者快速定位應用程序中的性能瓶頸。通過分析哪些函數調用最頻繁或哪些調用耗時最長,開發者可以集中優化這些熱點區域,從而提高整體應用性能。

資源使用分析:它可以幫助開發者理解應用程序如何使用系統資源,例如CPU和內存。這對于識別和修復內存泄漏、過度的CPU使用等問題非常重要。

代碼質量改進:通過堆棧統計,開發者可以識別代碼中的不良實踐或設計模式,如不必要的遞歸、過度復雜的函數調用等,進而重構代碼以提高其可讀性和可維護性。

優化決策依據:堆棧統計提供了量化數據,幫助開發團隊做出基于數據的決策。這些數據可以用來確定優化的優先級,決定哪些優化措施可以帶來最大的性能提升。

性能回歸檢測:在軟件開發周期中,新的代碼提交可能會引入性能回歸。定期進行堆棧統計可以幫助及時發現性能下降,確保軟件性能持續穩定。

用戶體驗提升:應用程序的響應速度直接影響用戶體驗。通過優化那些影響性能的關鍵部分,可以顯著提升應用的響應速度和流暢度,從而提高用戶滿意度。

成本效益分析:對于需要大量計算資源的應用程序,堆棧統計可以幫助識別和優化資源密集型操作,從而減少對硬件資源的需求,降低運營成本。

總之,堆棧統計是理解和優化軟件性能的強大工具。通過定期進行堆棧統計和分析,開發團隊可以確保他們的應用程序運行高效,提供優秀的用戶體驗,并以最佳的資源使用效率運作。

人工 VS 工具統計

在有相關統計工具之前,嵌入式系統的堆棧都是人工統計。此舉雖然可行,但是實際操作中存在許多問題和不足。

耗時耗力燒腦。人工統計需要徹底了解函數調用的深度、所有局部變量的細節,以及執行過程中隨時發生的中斷幀的大小對于復雜的嵌入式系統而言幾乎是不可行的。

漫長而又容易出錯的過程

沒法保證準確性,特別是在面對大量并發執行的任務和復雜的函數調用關系時,更是這樣。

實時更新,則更是無法做到,每一次代碼的變更,可能都需要做大量的重新統計。

工具分析能夠詳細分析出函數調用深度、局部變量和返回參數的堆棧估計、嵌套中斷以及執行期間發生的中斷幀的大小,解決人工統計的上述問題之外,還有另外兩個優勢。

動態分析:一些高級的堆棧統計工具支持運行時分析,能夠實時監控堆棧的使用情況,及時發現潛在的堆棧溢出風險。這種一般是芯片廠家或者合作廠家提供的調試工具中。

能夠對目標機進行測試和測量。對戰統計最好在真實硬件上獲得實際的堆棧使用量數據。許多開發環境都具有硬件模擬功能,并提供實時堆棧分析功能。在實際硬件上執行堆棧分析,并創建溢出場景來測試故障安全例程

可視化效果好。許多工具提供圖形化界面,直觀展示堆棧的使用情況,函數調用情況以及隨著函數調用,堆棧使用的變化,幫助開發者更容易理解和分析數據。

市面上常見的堆棧統計軟件

堆棧統計工具有以下幾類

一類是由編譯和 調試工具,有芯片廠商提供的,也有第三方的。比如 ARM Keil MDK,IAR Embedded Workbench 等等

第二類是第三方的調試工具,GNU 項目,如 GNU Debugger,Lauterbach Trace32

第三類是開源堆棧工具,如 Valgrind,FreeRTOS 中的 vTaskList

最后一類是靜態分析工具。這一類以 polyspace code prover 為代表。

以上就是關于內存、堆棧方面的一些介紹,以及常見的一些內存泄露相關的例子,這些例子會直接或間接到導致內存泄露,進而導致可用堆棧的減少,軟件長時間運行會導致性能下降,甚至崩潰等問題。處理好這些問題是解決堆棧問題的前提。

另外并介紹了堆棧統計的收益。

下一篇我們看看,如何使用形式化工具進行堆棧統計。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 嵌入式
    +關注

    關注

    5068

    文章

    19014

    瀏覽量

    303231
  • 計算機
    +關注

    關注

    19

    文章

    7418

    瀏覽量

    87712
  • 內存
    +關注

    關注

    8

    文章

    2998

    瀏覽量

    73881
  • C語言
    +關注

    關注

    180

    文章

    7598

    瀏覽量

    136174
  • 堆棧
    +關注

    關注

    0

    文章

    182

    瀏覽量

    19731

原文標題:堆棧統計知多少(一)關于內存,堆棧和常見的 BUG

文章出處:【微信號:MATLAB,微信公眾號:MATLAB】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    堆棧內存和堆內存之間的區別

    編寫有效的代碼需要了解堆棧和堆內存,這使其成為學習編程的重要組成部分。不僅如此,新程序員或職場老手都應該完全熟悉堆棧內存和堆內存之間的區別,
    發表于 08-07 12:23 ?702次閱讀
    <b class='flag-5'>堆棧</b><b class='flag-5'>內存</b>和堆<b class='flag-5'>內存</b>之間的區別

    電工基本知識

    電工基本知識
    發表于 09-21 16:34 ?0次下載
    電工<b class='flag-5'>基本知識</b>

    LDO基本知識

    LDO基本知識
    發表于 02-09 10:26 ?103次下載
    LDO<b class='flag-5'>基本知識</b>

    MIMO 的基本知識介紹

    MIMO 的基本知識介紹 很好的初學者入門書籍
    發表于 06-25 14:47 ?25次下載

    功率MOSFET的基本知識

    功率MOSFET的基本知識
    發表于 04-16 23:34 ?2335次閱讀
    功率MOSFET的<b class='flag-5'>基本知識</b>

    繼電器基本知識

    繼電器基本知識
    發表于 06-30 19:28 ?1828次閱讀

    網絡基本知識教程

    網絡基本知識教程
    發表于 01-13 12:55 ?1570次閱讀

    HFC網絡基本知識

    HFC網絡的基本知識講解
    發表于 11-08 17:30 ?59次下載
    HFC網絡<b class='flag-5'>基本知識</b>

    LED基本知識

    介紹LED的基本知識以及LED的分類。
    發表于 05-30 14:58 ?0次下載

    安全用電基本知識

    安全用電基本知識安全用電基本知識安全用電基本知識
    發表于 01-14 15:54 ?0次下載

    UPS電源的基本知識

    電子專業單片機相關知識學習教材資料——UPS電源的基本知識
    發表于 09-13 17:46 ?0次下載

    光纖基本知識

    光纖基本知識
    發表于 12-15 22:26 ?0次下載

    線程的基本知識

    【RT-Thread】線程的基本知識
    的頭像 發表于 02-04 15:42 ?3443次閱讀
    線程的<b class='flag-5'>基本知識</b>

    CPLD/FPGA的基本知識

    CPLD/FPGA的基本知識講解。
    發表于 03-30 09:55 ?31次下載
    CPLD/FPGA的<b class='flag-5'>基本知識</b>

    電氣基本知識科普

    電氣基本知識科普
    的頭像 發表于 09-09 10:23 ?6048次閱讀
    電氣<b class='flag-5'>基本知識</b>科普