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

永遠也不完美的程序

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

常用鏈接

統計

積分與排名

好友鏈接

最新評論

堆和棧(轉)

堆(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>
            美女福利精品视频| 国产精品初高中精品久久| 亚洲欧美激情视频| 久久不射2019中文字幕| 欧美激情区在线播放| 一区二区三区黄色| 欧美日韩国产专区| 亚洲六月丁香色婷婷综合久久| 欧美1区免费| 亚洲国产精品一区制服丝袜| 欧美日本不卡| 影音先锋久久| 欧美一区二区三区日韩| 亚洲最新中文字幕| 国产精品久久久久久久午夜| 久久久国产精品一区| 欧美极品aⅴ影院| 欧美三级网页| 欧美中文字幕第一页| 国产精品免费在线| 亚洲精品国产精品国自产在线 | 亚洲乱码国产乱码精品精可以看| 免费一级欧美片在线播放| 亚洲一区二区三区影院| 中文久久乱码一区二区| 日韩视频―中文字幕| 欧美亚洲在线视频| 久久亚洲私人国产精品va| 欧美成人精品1314www| 亚洲精品一区二区三区婷婷月| 亚洲成色精品| 久久国产高清| 亚洲精品乱码久久久久| 亚洲一区二区在线免费观看视频 | 亚洲精品日韩欧美| 亚洲欧美一区二区视频| 国产日韩欧美在线看| 久久久www成人免费无遮挡大片| 久久国产精品电影| 亚洲国产毛片完整版| 欧美电影免费观看高清| 国产精品成人在线| 亚洲免费精品| 99精品视频免费观看| 欧美精品在线视频观看| 亚洲网友自拍| 亚洲欧洲一区二区三区久久| 亚洲黑丝一区二区| 国产日韩欧美精品一区| 一本色道久久综合亚洲精品高清| 你懂的网址国产 欧美| 亚洲免费观看在线观看| 国产精品久久久久91| 久久久久久噜噜噜久久久精品| 国产精品丝袜白浆摸在线| 日韩亚洲欧美中文三级| 欧美11—12娇小xxxx| 欧美在线你懂的| 久久久精品一区二区三区| 亚洲伦理在线| 久久国产直播| 亚洲日本欧美日韩高观看| aa级大片欧美三级| 欧美午夜女人视频在线| 亚洲欧洲一区二区三区| 亚洲无线一线二线三线区别av| 美女脱光内衣内裤视频久久影院| 亚洲激情在线观看| 亚洲无毛电影| 欧美国产日韩精品| 亚洲精品四区| 免费久久精品视频| 亚洲美女黄网| 午夜在线精品| 亚洲视频图片小说| 欧美一级专区| 欧美在线播放| 尤物yw午夜国产精品视频明星| 欧美电影电视剧在线观看| 久久精品视频在线免费观看| 99精品视频免费全部在线| 久久爱www久久做| 亚洲欧美日韩成人高清在线一区| 欧美一二三视频| 久久先锋资源| 夜夜夜精品看看| 性欧美精品高清| 亚洲日韩欧美一区二区在线| 亚洲午夜久久久久久尤物 | 欧美国产一区在线| 亚洲第一区中文99精品| 亚洲国产一区二区精品专区| 国产精品分类| 欧美成人免费在线观看| 亚洲国产一区二区精品专区| 亚洲国产精品久久久久秋霞蜜臀| 在线免费观看日本欧美| 欧美国产丝袜视频| 国内偷自视频区视频综合| 一区二区三区**美女毛片| 加勒比av一区二区| 日韩一级精品| 亚洲精品三级| 久久久另类综合| 午夜精品理论片| 国产精品高潮呻吟| 一区二区不卡在线视频 午夜欧美不卡在 | 久久综合给合久久狠狠色| 国产精品久久久久av| 亚洲成色精品| 猛男gaygay欧美视频| 国产九九精品| 久久久精品性| 小黄鸭精品密入口导航| 亚洲毛片在线| 欧美成人在线影院| 亚洲精品日产精品乱码不卡| 一区二区三区免费网站| 欧美理论在线播放| 免费试看一区| 亚洲九九九在线观看| 国产精品日韩一区二区| 麻豆国产精品777777在线| 国产情侣久久| 国产精品福利久久久| 亚洲性感激情| 老司机aⅴ在线精品导航| 亚洲一区精品视频| 国产伦精品一区二区三区高清| 欧美成人国产一区二区| 亚洲精品一品区二品区三品区| 亚洲九九九在线观看| 久久成人这里只有精品| 国产精品青草综合久久久久99| 蜜臀av国产精品久久久久| 中国日韩欧美久久久久久久久| 久久久久一区二区三区四区| 亚洲盗摄视频| 亚洲人成绝费网站色www| 国产精品theporn88| 久久狠狠婷婷| 性8sex亚洲区入口| 久久精品国产精品亚洲| 久久久精品免费视频| 另类专区欧美制服同性| 巨乳诱惑日韩免费av| 久久久亚洲高清| 午夜精品久久久久久久| 激情久久一区| 最新国产成人在线观看| 久久婷婷国产综合精品青草| 亚洲视频1区2区| 中文精品视频| 欧美 日韩 国产 一区| 久久亚洲精品中文字幕冲田杏梨 | 欧美高清视频在线播放| 久久久国际精品| 欧美一级在线视频| 亚洲麻豆av| 久久久综合香蕉尹人综合网| 欧美精品亚洲二区| 亚洲国产天堂久久综合| 国产精品久久久久久久免费软件| 亚洲在线观看免费| 欧美 日韩 国产在线| 国产精品毛片va一区二区三区| 欧美区二区三区| 欧美电影电视剧在线观看| 亚洲你懂的在线视频| 免费短视频成人日韩| 久久免费视频在线| 国产亚洲成av人在线观看导航 | 久久日韩粉嫩一区二区三区| 欧美激情亚洲激情| 国产亚洲精品高潮| 欧美成人免费va影院高清| 久久久久久久激情视频| 最新国产精品拍自在线播放| 久久久xxx| 美日韩在线观看| 亚洲国产精品va在看黑人| 亚洲精品在线一区二区| 蜜桃精品久久久久久久免费影院| 香蕉久久一区二区不卡无毒影院| 国产日韩欧美精品一区| 亚洲国产另类精品专区| 亚洲欧美日韩国产| 国产欧美日韩免费看aⅴ视频| 在线免费观看一区二区三区| 亚洲精品美女91| 欧美日本免费| 亚洲国产婷婷| 日韩一二在线观看| 久久久亚洲综合| 欧美国产日韩一区| 亚洲欧洲另类| 亚洲免费网站| 免费不卡在线观看av| 激情久久中文字幕| 久久久久久久尹人综合网亚洲|