• <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>
            posts - 297,  comments - 15,  trackbacks - 0

            堆: 是大家共有的空間,分全局堆和局部堆。全局堆就是所有沒有分配的空間,局部堆就是用戶分配的空間。堆在操作系統(tǒng)對進(jìn)程初始化的時(shí)候分配,運(yùn)行過程中也可以向系統(tǒng)要額外的堆,但是記得用完了要還給操作系統(tǒng),要不然就是內(nèi)存泄漏。

            棧:是個(gè)線程獨(dú)有的,保存其運(yùn)行狀態(tài)和局部自動(dòng)變量的。棧在線程開始的時(shí)候初始化,每個(gè)線程的?;ハ嗒?dú)立,因此,棧是 thread safe的。每個(gè)C?。珜ο蟮臄?shù)據(jù)成員也存在在棧中,每個(gè)函數(shù)都有自己的棧,棧被用來在函數(shù)之間傳遞參數(shù)。操作系統(tǒng)在切換線程的時(shí)候會自動(dòng)的切換棧,就是切換?。樱樱牛樱屑拇嫫?。??臻g不需要在高級語言里面顯式的分配和釋放。

            堆和棧的區(qū)別

            一、預(yù)備知識—程序的內(nèi)存分配
            一個(gè)由c/C++編譯的程序占用的內(nèi)存分為以下幾個(gè)部分:
            1、棧區(qū)(stack)— 由編譯器自動(dòng)分配釋放,存放函數(shù)的參數(shù)值,局部變量的值等。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧。

            2、堆區(qū)(heap) — 一般由程序員分配釋放,若程序員不釋放,程序結(jié)束時(shí)可能由OS回收。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事,分配方式倒是類似于鏈表。

            3、全局區(qū)(靜態(tài)區(qū))(static)—,全局變量和靜態(tài)變量的存儲是放在一塊的,初始化的全局變量和靜態(tài)變量在一塊區(qū)域,未初始化的全局變量和未初始化的靜態(tài)變量在相鄰的另一塊區(qū)域。 - 程序結(jié)束后由系統(tǒng)釋放。

            4、文字常量區(qū)   —常量字符串就是放在這里的。程序結(jié)束后由系統(tǒng)釋放。

            5、程序代碼區(qū)—存放函數(shù)體的二進(jìn)制代碼。

            二、例子程序
            //main.cpp
            int a = 0; 全局初始化區(qū)
            char *p1; 全局未初始化區(qū)
            main()
            {
            int b; 棧
            char s[] = "abc"; 棧
            char *p2; 棧
            char *p3 = "123456"; 123456\0在常量區(qū),p3在棧上。
            static int c =0;全局(靜態(tài))初始化區(qū)
            p1 = (char *)malloc(10);
            p2 = (char *)malloc(20);
            分配得來得10和20字節(jié)的區(qū)域就在堆區(qū)。
            strcpy(p1, "123456"); 123456\0放在常量區(qū),編譯器可能會將它與p3所指向的"123456"優(yōu)化成一個(gè)地方。
            }
            二、堆和棧的理論知識
            2.1申請方式
            stack:
            由系統(tǒng)自動(dòng)分配。例如,聲明在函數(shù)中一個(gè)局部變量 int b; 系統(tǒng)自動(dòng)在棧中為b開辟空間
            heap:
            需要程序員自己申請,并指明大小,在c中malloc函數(shù)
            如p1 = (char *)malloc(10);
            在C++中用new運(yùn)算符
            如p2 = (char *)malloc(10);
            但是注意p1、p2本身是在棧中的。


            2.2
            申請后系統(tǒng)的響應(yīng)
            棧:只要棧的剩余空間大于所申請空間,系統(tǒng)將為程序提供內(nèi)存,否則將報(bào)異常提示棧溢出。
            堆: 首先應(yīng)該知道操作系統(tǒng)有一個(gè)記錄空閑內(nèi)存地址的鏈表,當(dāng)系統(tǒng)收到程序的申請時(shí),會遍歷該鏈表,尋找第一個(gè)空間大于所申請空間的堆結(jié)點(diǎn),然后將該結(jié)點(diǎn)從空閑 結(jié)點(diǎn)鏈表中刪除,并將該結(jié)點(diǎn)的空間分配給程序,另外,對于大多數(shù)系統(tǒng),會在這塊內(nèi)存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語句才能正確的釋放本內(nèi)存空間。另外,由于找到的堆結(jié)點(diǎn)的大小不一定正好等于申請的大小,系統(tǒng)會自動(dòng)的將多余的那部分重新放入空閑鏈表中。

            2.3申請大小的限制
            棧:在Windows下,棧是向低地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是一塊連續(xù)的內(nèi)存的區(qū)域。這句話的意思是棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的,在WINDOWS下,棧的大小是2M(也可能是1M,它是一個(gè)編譯時(shí)就確定的常數(shù)),如果申請的空間超過棧的剩余空間時(shí),將提示overflow。因此,能從棧獲得的空間較小

            堆:堆是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。這是由于系統(tǒng)是用鏈表來存儲的空閑內(nèi)存地址的,自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計(jì)算機(jī)系統(tǒng)中有效的虛擬內(nèi)存。由此可見,堆獲得的空間比較靈活,也比較大。


            2.4申請效率的比較:
            棧由系統(tǒng)自動(dòng)分配,速度較快。但程序員是無法控制的。
            堆是由new分配的內(nèi)存,一般速度比較慢,而且容易產(chǎn)生內(nèi)存碎片,不過用起來最方便.
            另外,在WINDOWS下,最好的方式是用VirtualAlloc分配內(nèi)存,他不是在堆,也不是在棧是直接在進(jìn)程的地址空間中保留一快內(nèi)存,雖然用起來最不方便。但是速度快,也最靈活。

            2.5堆和棧中的存儲內(nèi)容
            棧:在函數(shù)調(diào)用時(shí),第一個(gè)進(jìn)棧的是主函數(shù)中后的下一條指令(函數(shù)調(diào)用語句的下一條可執(zhí)行語句)的地址,然后是函數(shù)的各個(gè)參數(shù),在大多數(shù)的C編譯器中,參數(shù)是由右往左入棧的,然后是函數(shù)中的局部變量。注意靜態(tài)變量是不入棧的。
            當(dāng)本次函數(shù)調(diào)用結(jié)束后,局部變量先出棧,然后是參數(shù),最后棧頂指針指向最開始存的地址,也就是主函數(shù)中的下一條指令,程序由該點(diǎn)繼續(xù)運(yùn)行。
            堆:一般是在堆的頭部用一個(gè)字節(jié)存放堆的大小。堆中的具體內(nèi)容有程序員安排。

            2.6存取效率的比較

            char s1[] = "aaaaaaaaaaaaaaa";
            char *s2 = "bbbbbbbbbbbbbbbbb";
            aaaaaaaaaaa是在運(yùn)行時(shí)刻賦值的;
            而bbbbbbbbbbb是在編譯時(shí)就確定的;
            但是,在以后的存取中,在棧上的數(shù)組比指針?biāo)赶虻淖址?例如堆)快。
            比如:
            void main()
            {
            char a = 1;
            char c[] = "1234567890";
            char *p ="1234567890";
            a = c[1];
            a = p[1];
            return;
            }
            對應(yīng)的匯編代碼
            10: a = c[1];
            00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
            0040106A 88 4D FC mov byte ptr [ebp-4],cl
            11: a = p[1];
            0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
            00401070 8A 42 01 mov al,byte ptr [edx+1]
            00401073 88 45 FC mov byte ptr [ebp-4],al
            第一種在讀取時(shí)直接就把字符串中的元素讀到寄存器cl中,而第二種則要先把指針值讀到edx中,在根據(jù)
            edx讀取字符,顯然慢了。


            2.7小結(jié):
            堆和棧的區(qū)別可以用如下的比喻來看出:
            使用棧就象我們?nèi)ワ堭^里吃飯,只管點(diǎn)菜(發(fā)出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等準(zhǔn)備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。
            使用堆就象是自己動(dòng)手做喜歡吃的菜肴,比較麻煩,但是比較符合自己的口味,而且自由度大。


            下面是另一篇,總結(jié)的比上面好:

            堆和棧的聯(lián)系與區(qū)別dd

                  在bbs上,堆與棧的區(qū)分問題,似乎是一個(gè)永恒的話題,由此可見,初學(xué)者對此往往是混淆不清的,所以我決定拿他第一個(gè)開刀。

                   首先,我們舉一個(gè)例子:

                   void f() { int* p=new int[5]; }

                   這條短短的一句話就包含了堆與棧,看到new,我們首先就應(yīng)該想到,我們分配了一塊堆內(nèi)存,那么指針p呢?他分配的是一塊棧內(nèi)存,所以這句話的意思就是: 在棧內(nèi)存中存放了一個(gè)指向一塊堆內(nèi)存的指針p。在程序會先確定在堆中分配內(nèi)存的大小,然后調(diào)用operator new分配內(nèi)存,然后返回這塊內(nèi)存的首地址,放入棧中,他在VC6下的匯編代碼如下:

                   00401028      push           14h

                   0040102A      call           operator new (00401060)

                   0040102F      add            esp,4

                   00401032      mov            dword ptr [ebp-8],eax

                   00401035      mov            eax,dword ptr [ebp-8]

                   00401038      mov            dword ptr [ebp-4],eax

                   這里,我們?yōu)榱撕唵尾]有釋放內(nèi)存,那么該怎么去釋放呢?是delete p么?澳,錯(cuò)了,應(yīng)該是delete []p,這是為了告訴編譯器:我刪除的是一個(gè)數(shù)組,VC6就會根據(jù)相應(yīng)的Cookie信息去進(jìn)行釋放內(nèi)存的工作。

                   好了,我們回到我們的主題:堆和棧究竟有什么區(qū)別?

                   主要的區(qū)別由以下幾點(diǎn):

                   1、管理方式不同;

                   2、空間大小不同;

                   3、能否產(chǎn)生碎片不同;

                   4、生長方向不同;

                   5、分配方式不同;

                   6、分配效率不同;

                   管理方式:對于棧來講,是由編譯器自動(dòng)管理,無需我們手工控制;對于堆來說,釋放工作由程序員控制,容易產(chǎn)生memory leak。

                   空間大小:一般來講在32位系統(tǒng)下,堆內(nèi)存可以達(dá)到4G的空間,從這個(gè)角度來看堆內(nèi)存幾乎是沒有什么限制的。但是對于棧來講,一般都是有一定的空間大小 的,例如,在VC6下面,默認(rèn)的??臻g大小是1M(好像是,記不清楚了)。當(dāng)然,我們可以修改:    

                   打開工程,依次操作菜單如下:Project->Setting->Link,在Category 中選中Output,然后在Reserve中設(shè)定堆棧的最大值和commit。

            注意:reserve最小值為4Byte;commit是保留在虛擬內(nèi)存的頁文件里面,它設(shè)置的較大會使棧開辟較大的值, 可能增加內(nèi)存的開銷和啟動(dòng)時(shí)間。

                   碎片問題:對于堆來講,頻繁的new/delete勢必會造成內(nèi)存空間的不連續(xù),從而造成大量的碎片,使程序效率降低。對于棧來講,則不會存在這個(gè)問題, 因?yàn)闂J窍冗M(jìn)后出的隊(duì)列,他們是如此的一一對應(yīng),以至于永遠(yuǎn)都不可能有一個(gè)內(nèi)存塊從棧中間彈出,在他彈出之前,在他上面的后進(jìn)的棧內(nèi)容已經(jīng)被彈出,詳細(xì)的 可以參考數(shù)據(jù)結(jié)構(gòu),這里我們就不再一一討論了。

                   生長方向:對于堆來講,生長方向是向上的,也就是向著內(nèi)存地址增加的方向;對于棧來講,它的生長方向是向下的,是向著內(nèi)存地址減小的方向增長。

                   分配方式:堆都是動(dòng)態(tài)分配的,沒有靜態(tài)分配的堆。棧有2種分配方式:靜態(tài)分配和動(dòng)態(tài)分配。靜態(tài)分配是編譯器完成的,比如局部變量的分配。動(dòng)態(tài)分配由 alloca函數(shù)進(jìn)行分配,但是棧的動(dòng)態(tài)分配和堆是不同的,他的動(dòng)態(tài)分配是由編譯器進(jìn)行釋放,無需我們手工實(shí)現(xiàn)。

                   分配效率:棧是機(jī)器系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu),計(jì)算機(jī)會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執(zhí)行,這就決定了棧的效率比 較高。堆則是C/C++函數(shù)庫提供的,它的機(jī)制是很復(fù)雜的,例如為了分配一塊內(nèi)存,庫函數(shù)會按照一定的算法(具體的算法可以參考數(shù)據(jù)結(jié)構(gòu)/操作系統(tǒng))在堆 內(nèi)存中搜索可用的足夠大小的空間,如果沒有足夠大小的空間(可能是由于內(nèi)存碎片太多),就有可能調(diào)用系統(tǒng)功能去增加程序數(shù)據(jù)段的內(nèi)存空間,這樣就有機(jī)會分 到足夠大小的內(nèi)存,然后進(jìn)行返回。顯然,堆的效率比棧要低得多。

                   從這里我們可以看到,堆和棧相比,由于大量new/delete的使用,容易造成大量的內(nèi)存碎片;由于沒有專門的系統(tǒng)支持,效率很低;由于可能引發(fā)用戶態(tài) 和核心態(tài)的切換,內(nèi)存的申請,代價(jià)變得更加昂貴。所以棧在程序中是應(yīng)用最廣泛的,就算是函數(shù)的調(diào)用也利用棧去完成,函數(shù)調(diào)用過程中的參數(shù),返回地 址,EBP和局部變量都采用棧的方式存放。所以,我們推薦大家盡量用棧,而不是用堆。

                   雖然棧有如此眾多的好處,但是由于和堆相比不是那么靈活,有時(shí)候分配大量的內(nèi)存空間,還是用堆好一些。

                   無論是堆還是棧,都要防止越界現(xiàn)象的發(fā)生(除非你是故意使其越界),因?yàn)樵浇绲慕Y(jié)果要么是程序崩潰,要么是摧毀程序的堆、棧結(jié)構(gòu),產(chǎn)生以想不到的結(jié)果,就 算是在你的程序運(yùn)行過程中,沒有發(fā)生上面的問題,你還是要小心,說不定什么時(shí)候就崩掉,那時(shí)候debug可是相當(dāng)困難的 :)    對了,還有一件事,如果有人把堆棧合起來說,那它的意思是棧,可不是堆,呵呵, 清楚了?


            from:
            http://blog.chinaunix.net/u2/76292/showart_1327414.html

            http://hi.baidu.com/54wangjun/blog/item/d1b4a74424d5934f510ffedd.html

            posted on 2009-12-11 23:53 chatler 閱讀(219) 評論(0)  編輯 收藏 引用 所屬分類: OS
            <2010年9月>
            2930311234
            567891011
            12131415161718
            19202122232425
            262728293012
            3456789

            常用鏈接

            留言簿(10)

            隨筆分類(307)

            隨筆檔案(297)

            algorithm

            Books_Free_Online

            C++

            database

            Linux

            Linux shell

            linux socket

            misce

            • cloudward
            • 感覺這個(gè)博客還是不錯(cuò),雖然做的東西和我不大相關(guān),覺得看看還是有好處的

            network

            OSS

            • Google Android
            • Android is a software stack for mobile devices that includes an operating system, middleware and key applications. This early look at the Android SDK provides the tools and APIs necessary to begin developing applications on the Android platform using the Java programming language.
            • os161 file list

            overall

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            色综合合久久天天给综看| 97久久国产露脸精品国产| 狠狠色婷婷久久一区二区| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 99久久99久久精品国产片果冻| 精品99久久aaa一级毛片| 青青草国产精品久久久久| 国产精品美女久久久| 国产国产成人久久精品| 国产韩国精品一区二区三区久久| 亚洲精品无码久久久久去q| 97精品伊人久久久大香线蕉| 久久无码AV中文出轨人妻| 一本久久免费视频| 综合久久精品色| 亚洲女久久久噜噜噜熟女| 亚洲色大成网站www久久九| 亚洲精品乱码久久久久久| 久久亚洲精品国产精品| 999久久久无码国产精品| 精品精品国产自在久久高清 | 狠狠88综合久久久久综合网| 丁香五月综合久久激情| 久久se精品一区二区影院| 伊人久久精品线影院| 久久精品二区| 久久久久国产精品嫩草影院| 久久精品国产2020| 国产精品久久久亚洲| 国产精品欧美亚洲韩国日本久久| 国产成人香蕉久久久久| 女人高潮久久久叫人喷水| 久久婷婷激情综合色综合俺也去| 国产成人精品久久一区二区三区| 精品久久久久久无码中文野结衣| 性高朝久久久久久久久久| 欧美喷潮久久久XXXXx| 国产精品久久自在自线观看| 午夜肉伦伦影院久久精品免费看国产一区二区三区 | 久久本道伊人久久| 综合久久给合久久狠狠狠97色 |