青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

永遠也不完美的程序

不斷學習,不斷實踐,不斷的重構……

常用鏈接

統計

積分與排名

好友鏈接

最新評論

堆和棧(轉)

堆(heap)和棧(stack)是C/C++編程不可避免會碰到的兩個基本概念。首先,這兩個概念都可以在講數據結構的書中找到,他們都是基本的數據結構,雖然棧更為簡單一些。在具體的C/C++編程框架中,這兩個概念并不是并行的。對底層機器代碼的研究可以揭示,棧是機器系統提供的數據結構,而堆則是C/C++函數庫提供的。

具體地說,現代計算機(串行執行機制),都直接在代碼底層支持棧的數據結構。這體現在,有專門的寄存器指向棧所在的地址,有專門的機器指令完成數據入棧出棧的操作。這種機制的特點是效率高,支持的數據有限,一般是整數,指針,浮點數等系統直接支持的數據類型,并不直接支持其他的數據結構。因為棧的這種特點,對棧的使用在程序中是非常頻繁的。對子程序的調用就是直接利用棧完成的。機器的call指令里隱含了把返回地址推入棧,然后跳轉至子程序地址的操作,而子程序中的ret指令則隱含從堆棧中彈出返回地址并跳轉之的操作。C/C++中的自動變量是直接利用棧的例子,這也就是為什么當函數返回時,該函數的自動變量自動失效的原因。

和棧不同,堆的數據結構并不是由系統(無論是機器系統還是操作系統)支持的,而是由函數庫提供的。基本的malloc/realloc/free函數維護了一套內部的堆數據結構。當程序使用這些函數去獲得新的內存空間時,這套函數首先試圖從內部堆中尋找可用的內存空間,如果沒有可以使用的內存空間,則試圖利用系統調用來動態增加程序數據段的內存大小,新分配得到的空間首先被組織進內部堆中去,然后再以適當的形式返回給調用者。當程序釋放分配的內存空間時,這片內存空間被返回內部堆結構中,可能會被適當的處理(比如和其他空閑空間合并成更大的空閑空間),以更適合下一次內存分配申請。這套復雜的分配機制實際上相當于一個內存分配的緩沖池(Cache),使用這套機制有如下若干原因:

1. 系統調用可能不支持任意大小的內存分配。有些系統的系統調用只支持固定大小及其倍數的內存請求(按頁分配);這樣的話對于大量的小內存分類來說會造成浪費。

2. 系統調用申請內存可能是代價昂貴的。系統調用可能涉及用戶態和核心態的轉換。

3. 沒有管理的內存分配在大量復雜內存的分配釋放操作下很容易造成內存碎片。

堆和棧的對比

從以上知識可知,棧是系統提供的功能,特點是快速高效,缺點是有限制,數據不靈活;而棧是函數庫提供的功能,特點是靈活方便,數據適應面廣泛,但是效率有一定降低。棧是系統數據結構,對于進程/線程是唯一的;堆是函數庫內部數據結構,不一定唯一。不同堆分配的內存無法互相操作。棧空間分靜態分配和動態分配兩種。靜態分配是編譯器完成的,比如自動變量(auto)的分配。動態分配由alloca函數完成。棧的動態分配無需釋放(是自動的),也就沒有釋放函數。為可移植的程序起見,棧的動態分配操作是不被鼓勵的!堆空間的分配總是動態的,雖然程序結束時所有的數據空間都會被釋放回系統,但是精確的申請內存/釋放內存匹配是良好程序的基本要素。





進程在內存中的影像.  
      我們假設現在有一個程序, 它的函數調用順序如下.  
      main(...) -> func_1(...) -> func_2(...) -> func_3(...)  
      即: 主函數main調用函數func_1; 函數func_1調用函數func_2; 函數func_2調用函數func_3  

      當程序被操作系統調入內存運行, 其相對應的進程在內存中的影像如下圖所示.  

        (內存高址)  
        +--------------------------------------+  
        |             ......                   |  ... 省略了一些我們不需要關心的區  
        +--------------------------------------+  
        |  env strings (環境變量字串)          | \  
        +--------------------------------------+  \  
        |  argv strings (命令行字串)           |   \  
        +--------------------------------------+    \  
        |  env pointers (環境變量指針)         |    SHELL的環境變量和命令行參數保存區  
        +--------------------------------------+    /  
        |  argv pointers (命令行參數指針)      |   /  
        +--------------------------------------+  /  
        |  argc (命令行參數個數)               | /  
        +--------------------------------------+  
        |            main 函數的棧幀           | \  
        +--------------------------------------+  \  
        |            func_1 函數的棧幀         |   \  
        +--------------------------------------+    \  
        |            func_2 函數的棧幀         |     \  
        +--------------------------------------+      \  
        |            func_3 函數的棧幀         |      Stack (棧)  
        +......................................+      /  
        |                                      |     /  
                      ......                        /  
        |                                      |   /  
        +......................................+  /  
        |            Heap (堆)                 | /  
        +--------------------------------------+  
        |        Uninitialised (BSS) data      |  非初始化數據(BSS)區  
        +--------------------------------------+  
        |        Initialised data              |  初始化數據區  
        +--------------------------------------+  
        |        Text                          |  文本區  
        +--------------------------------------+  
        (內存低址)  

        這里需要說明的是:  
        i)   隨著函數調用層數的增加, 函數棧幀是一塊塊地向內存低地址方向延伸的.  
             隨著進程中函數調用層數的減少, 即各函數調用的返回, 棧幀會一塊塊地  
             被遺棄而向內存的高址方向回縮.  
             各函數的棧幀大小隨著函數的性質的不同而不等, 由函數的局部變量的數目決定.  
        ii)  進程對內存的動態申請是發生在Heap(堆)里的. 也就是說, 隨著系統動態分  
             配給進程的內存數量的增加, Heap(堆)有可能向高址或低址延伸, 依賴于不  
             同CPU的實現. 但一般來說是向內存的高地址方向增長的.  
        iii) 在BSS數據或者Stack(棧)的增長耗盡了系統分配給進程的自由內存的情況下,  
             進程將會被阻塞, 重新被操作系統用更大的內存模塊來調度運行.  
             (雖然和exploit沒有關系, 但是知道一下還是有好處的)  
        iv)  函數的棧幀里包含了函數的參數(至于被調用函數的參數是放在調用函數的棧  
             幀還是被調用函數棧幀, 則依賴于不同系統的實現),  
             它的局部變量以及恢復調用該函數的函數的棧幀(也就是前一個棧幀)所需要的  
             數據, 其中包含了調用函數的下一條執行指令的地址.  
        v)   非初始化數據(BSS)區用于存放程序的靜態變量, 這部分內存都是被初始化為零的.  
             初始化數據區用于存放可執行文件里的初始化數據.  
             這兩個區統稱為數據區.  
        vi)  Text(文本區)是個只讀區, 任何嘗試對該區的寫操作會導致段違法出錯. 文本區  
             是被多個運行該可執行文件的進程所共享的. 文本區存放了程序的代碼.  

    2) 函數的棧幀.  
       函數調用時所建立的棧幀包含了下面的信息:  
       i)   函數的返回地址. 返回地址是存放在調用函數的棧幀還是被調用函數的棧幀里,  
            取決于不同系統的實現.  
       ii)  調用函數的棧幀信息, 即棧頂和棧底.  
       iii) 為函數的局部變量分配的空間  
       iv)  為被調用函數的參數分配的空間--取決于不同系統的實現.

posted on 2009-05-16 23:52 狂爛球 閱讀(2556) 評論(4)  編輯 收藏 引用 所屬分類: C++

評論

# re: 堆和棧(轉) 2009-05-17 12:22 skyscribe

解釋的很清楚哦,不錯!

補充一點:
函數的參數可能是在寄存器上而不是在棧上。
gcc那個著名的優化選項-fomit-frame-pointer還可以把fp指針占用的寄存器空間給省略掉從而帶來性能的提升。  回復  更多評論   

# re: 堆和棧(轉) 2009-05-17 12:28 maomi

niubi, 學習了. thanks  回復  更多評論   

# re: 堆和棧(轉)[未登錄] 2009-05-18 00:17 zj

引用:堆的數據結構并不是由系統(無論是機器系統還是操作系統)支持的,而是由函數庫提供的.
----------------------------------
應該是有系統提供的,操作系統幾大組件,內存管理,文件管理。
不是系統提供內存管理系統調用,庫函數只是空中樓閣,必定庫函數也是封裝了系統調用  回復  更多評論   

# re: 堆和棧(轉) 2009-05-18 11:20 yb

@zj
沒錯,malloc,free之類的函數需要系統支持,這就是為什么不同的平臺移植時往往要重寫malloc, free。  回復  更多評論   


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美黄色一区| 亚洲国产精品一区二区三区| 欧美成人精品不卡视频在线观看 | 亚洲综合色噜噜狠狠| 亚洲人成网站777色婷婷| 91久久精品美女高潮| 日韩视频一区二区三区| 一区二区三区偷拍| 欧美影视一区| 久久久一二三| 欧美精品v日韩精品v国产精品 | 一本一本久久a久久精品综合妖精| 日韩午夜av| 亚洲综合999| 噜噜噜在线观看免费视频日韩| 欧美国产乱视频| 一区二区三区四区五区精品| 欧美伊人久久久久久久久影院| 亚洲成人中文| 宅男噜噜噜66一区二区66| 欧美在线看片| 欧美精品导航| 国产视频久久久久| 亚洲欧洲在线视频| 亚洲欧美日产图| 欧美暴力喷水在线| 一本色道久久综合精品竹菊| 久久久精品一品道一区| 亚洲第一福利视频| 国产精品99久久久久久有的能看| 欧美在线视频一区二区| 欧美精品自拍| 一区在线电影| 欧美一级黄色网| 亚洲人成在线播放| 久久精品国产一区二区电影 | 在线观看国产日韩| 亚洲一本视频| 美女精品自拍一二三四| 亚洲一区二区精品| 欧美a级一区二区| 国内精品久久久久久久影视麻豆 | 91久久夜色精品国产九色| 亚洲欧美日韩综合| 欧美日韩国产不卡| 亚洲精品国产精品久久清纯直播| 欧美呦呦网站| 一二三区精品| 欧美精品性视频| 在线看片成人| 久久免费国产| 欧美亚洲一级片| 欧美视频在线观看视频极品| 欧美承认网站| 精品成人一区| 久久精品女人的天堂av| 亚洲一区二区成人在线观看| 欧美日韩高清在线播放| 最新高清无码专区| 噜噜噜在线观看免费视频日韩| 亚洲欧美日韩在线综合| 国产精品草莓在线免费观看| 欧美日韩精品是欧美日韩精品| 国模私拍视频一区| 欧美一区午夜视频在线观看| 一本久久知道综合久久| 欧美日韩免费看| 欧美日韩在线另类| 中文在线一区| 亚洲一区二区av电影| 国产精品久久久一区二区| 亚洲性视频网址| 国产精品99久久99久久久二8 | 亚洲国产精品国自产拍av秋霞| 久久婷婷国产综合精品青草| 久久亚洲不卡| 美女尤物久久精品| 亚洲日韩中文字幕在线播放| 亚洲黄页视频免费观看| 欧美激情性爽国产精品17p| 日韩一区二区久久| 亚洲视频一区在线观看| 亚洲一区国产精品| 国产日韩欧美夫妻视频在线观看| 久久超碰97人人做人人爱| 欧美在线亚洲综合一区| 亚洲第一精品夜夜躁人人躁| 亚洲激情社区| 欧美视频中文一区二区三区在线观看| 一区二区三区四区五区在线| 亚洲在线视频观看| 在线观看精品视频| 亚洲激情精品| 国产乱码精品一区二区三区av| 久久综合狠狠综合久久综青草 | 欧美成人一区二区| 欧美精品在线网站| 欧美在线视频一区二区| 久久精品免费电影| 亚洲毛片网站| 欧美在线一二三区| 日韩写真在线| 久久久国产精品一区| 亚洲精品欧美日韩| 亚洲午夜一区二区| 亚洲欧洲日韩综合二区| 亚洲一区二区精品在线| 在线观看日产精品| 一本色道久久| 在线精品视频一区二区三四| 亚洲午夜在线观看视频在线| 亚洲第一页在线| 亚洲欧美在线免费观看| 夜夜嗨av一区二区三区中文字幕| 欧美淫片网站| 欧美一区二区三区喷汁尤物| 欧美寡妇偷汉性猛交| 久久婷婷麻豆| 国产日韩精品一区| 在线一区二区三区四区五区| 一区二区三区自拍| 午夜国产一区| 午夜在线a亚洲v天堂网2018| 欧美精品日日鲁夜夜添| 久久综合久久综合这里只有精品| 国产精品国产三级国产a| 最新日韩中文字幕| 欧美成人亚洲成人日韩成人| 美女脱光内衣内裤视频久久网站| 国产精品视频免费在线观看| 亚洲精品一区二区三区婷婷月| 伊人婷婷欧美激情| 欧美在线播放高清精品| 欧美一区二区三区婷婷月色 | 国产精品久久久亚洲一区 | 午夜精品在线观看| 性欧美暴力猛交另类hd| 国产精品久久77777| 一区二区激情小说| 亚洲自拍偷拍一区| 国产精品嫩草影院一区二区| 在线一区二区三区做爰视频网站| 夜夜嗨av一区二区三区四季av| 亚洲精品久久视频| 99精品国产在热久久| 欧美激情综合| 亚洲精品一区二| 亚洲免费影视| 国产精品视频第一区| 亚洲欧美综合一区| 久久婷婷国产综合精品青草 | 国产精品久久久久久模特 | 欧美一区91| 久久亚洲国产精品一区二区| 一区在线电影| 欧美99久久| 日韩视频一区二区| 小黄鸭视频精品导航| 国产欧美日韩视频在线观看| 久久超碰97中文字幕| 蜜臀av性久久久久蜜臀aⅴ四虎| 亚洲电影免费观看高清完整版在线观看| 久久久久久久久久久成人| 亚洲第一综合天堂另类专| 欧美a级理论片| 夜夜嗨av一区二区三区中文字幕| 亚洲少妇一区| 国语自产精品视频在线看抢先版结局| 久久影院亚洲| 亚洲免费激情| 久久亚洲精品视频| 日韩午夜在线| 国产区在线观看成人精品| 久久精品女人| 亚洲一区二区在线| 国产一区二区0| 欧美精品一区二区三区久久久竹菊| 99ri日韩精品视频| 久久性天堂网| 亚洲一区二区在线免费观看视频 | 亚洲欧美日韩国产成人| 尤妮丝一区二区裸体视频| 欧美欧美天天天天操| 欧美一区二区在线观看| 亚洲国产成人午夜在线一区| 性欧美大战久久久久久久免费观看| 在线精品国产欧美| 欧美三日本三级少妇三2023 | 欧美va天堂在线| 亚洲欧美日韩一区二区三区在线观看| 激情综合色综合久久| 欧美日韩国产综合视频在线观看 | 久久久久久综合| 一区二区三区久久| 亚洲成人在线免费| 国产欧美精品在线观看| 99av国产精品欲麻豆| 麻豆久久精品| 久久国产精品久久久久久电车| 99v久久综合狠狠综合久久|