栈大小和内存分部问题
今天面試問(wèn)了一個(gè)棧大小問(wèn)題,問(wèn)過(guò)兩次內(nèi)存的結(jié)構(gòu)問(wèn)題,都沒(méi)有答好,這次要弄清楚才行。
棧大小是有默認(rèn)值的,如果申請(qǐng)的臨時(shí)變量太大的話就會(huì)超過(guò)棧大小,造成棧溢出。
編譯期限制棧大小,和系統(tǒng)限制棧深度根本是兩回事。系統(tǒng)限制棧深是限制進(jìn)程主線程的棧深,限制的是整個(gè)函數(shù)調(diào)用鏈的最大棧深,這個(gè)棧深是函數(shù)調(diào)用鏈上各個(gè)函數(shù)棧幀大小之和。編譯期限制棧大小是限制單個(gè)函數(shù)棧幀的大小。
一、修改棧大小
棧的大小可以修改的。在應(yīng)用程序我們經(jīng)常需要定義大的數(shù)組,數(shù)組定義成局部變量非靜態(tài)變量,那么數(shù)組就會(huì)在棧上分配,當(dāng)數(shù)組超過(guò)默認(rèn)棧的大小時(shí),會(huì)引起非常內(nèi)存訪問(wèn)。那么如何修改系統(tǒng)默認(rèn)的棧的大小呢。
一般,在Unix-like平臺(tái),棧的大小不是由程序自己來(lái)控制的而是由環(huán)境變量來(lái)控制的,所以就不能通過(guò)設(shè)置編譯器(像gcc)的任何編譯標(biāo)志來(lái)設(shè)置棧的大小;在windows平臺(tái)下,棧的大小的信息是包含在可執(zhí)行文件中的。它可以在Visual C++的編譯過(guò)程中設(shè)置,但是在gcc中是不可行的。
方法為
項(xiàng)目->屬性->鏈接器->系統(tǒng)->堆棧保留大小
注:這里填的是字節(jié)數(shù)
?
在一般情況下, 不同平臺(tái)默認(rèn)棧大小如下(僅供參考)
SunOS/Solaris 8172K bytes (Shared Version)
Linux 10240K bytes
Windows?1024K?bytes (Release Version)
AIX 65536K bytes
如果定義大數(shù)組的情況下,那就需要修改默認(rèn)的棧大小,下面給出幾個(gè)平臺(tái)的修改方法:
1.SunOS/Solaris系統(tǒng):
limit # 顯示當(dāng)前用戶的棧大小?
unlimit?# 將當(dāng)前用戶的棧大小改為不限制大小
setenv STACKSIZE 32768 #設(shè)置當(dāng)前用戶的棧大小為 32M bytes
?
2.Linux系統(tǒng):
ulimit -a #顯示當(dāng)前用戶的棧大小
ulimit -s 32768 #將當(dāng)前用戶的棧大小設(shè)置為32M bytes
?
3. Windows (在編譯過(guò)程中的設(shè)置):
1). 選擇 "Project->Setting".
2). 選擇 "Link".
3. 選擇 "Category"中的 "Output".
?
4. 在 "Stack allocations"中的"Reserve:"中輸棧的大小,例如: 32768?
在 Visual Studio 開(kāi)發(fā)環(huán)境中設(shè)置此鏈接器選項(xiàng)
- 打開(kāi)此項(xiàng)目的“屬性頁(yè)”對(duì)話框。有關(guān)詳細(xì)信息,請(qǐng)參見(jiàn)設(shè)置 Visual C++ 項(xiàng)目屬性。
- 單擊“鏈接器”文件夾。
- 單擊“系統(tǒng)”屬性頁(yè)。
- 修改下列任一屬性:
- 堆棧提交大小
- 堆棧保留大小?
問(wèn)題解答:
方法一:STACKSIZE???定義.def文件
?
?????語(yǔ)法:STACKSIZE reserve[,commit]
???? reserve:棧的大小;commit:可選項(xiàng),與操作系統(tǒng)有關(guān),在NT上只一次分配物理內(nèi)存的大小
?
方法二:設(shè)定/STACK
???? VC6.0修改:
?????打開(kāi)工程,依次操作菜單如下:Project->Setting->Link,在Category 中選中Output,然后
在Reserve中設(shè)定堆棧的最大值和commit。
注意:reserve默認(rèn)值為1MB,最小值為4Byte;commit是保留在虛擬內(nèi)存的頁(yè)文件里面,它設(shè)置的較
大會(huì)使棧開(kāi)辟較大的值,可能增加內(nèi)存的開(kāi)銷和啟動(dòng)時(shí)間
二、堆大小
堆大小是可以自己申請(qǐng)的,只要不超過(guò)內(nèi)存都是可以的。
對(duì)于堆來(lái)講,頻繁的malloc/free(new/delete)勢(shì)必會(huì)造成內(nèi)存空間的不連續(xù),從而造成大量的碎片,使程序效率降低(雖然程序在退出后操作系統(tǒng)會(huì)對(duì)內(nèi)存進(jìn)行回收管理)。對(duì)于棧來(lái)講,則不會(huì)存在這個(gè)問(wèn)題。
三、C程序內(nèi)存分配
C程序一般分為 1.程序段:程序段為程序代碼在內(nèi)存中的映射.一個(gè)程序可以在內(nèi)存中多有個(gè)副本. 2.初始化過(guò)的數(shù)據(jù):在程序運(yùn)行值初已經(jīng)對(duì)變量進(jìn)行初始化的 3.未初始化過(guò)的數(shù)據(jù):在程序運(yùn)行初未對(duì)變量進(jìn)行初始化的數(shù)據(jù) 4.堆(stack):存儲(chǔ)局部,臨時(shí)變量,在程序塊開(kāi)始時(shí)自動(dòng)分配內(nèi)存,結(jié)束時(shí)自動(dòng)釋放內(nèi)存.存儲(chǔ)函數(shù)的返回指針. 5.棧(heap):存儲(chǔ)動(dòng)態(tài)內(nèi)存分配,需要程序員手工分配,手工釋放. 6.文字常量區(qū)—常量字符串就是放在這里的。程序結(jié)束后由系統(tǒng)釋放 附程序分布圖: id="iframe_0.44376118294894695" src="data:text/html;charset=utf8,%3Cimg%20id=%22img%22%20src=%22http://blog.chinaunix.net/photo/85561_081230114738.jpg?_=3987181%22%20style=%22border:none;max-width:967px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.44376118294894695',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no" style="border-style: none; border-width: initial; width: 512px; height: 384px;">| id="iframe_0.15878063929267228" src="data:text/html;charset=utf8,%3Cimg%20id=%22img%22%20src=%22http://book.51cto.com/files/uploadimg/20081108/2059580.jpg?_=3987181%22%20style=%22border:none;max-width:967px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.15878063929267228',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no" style="border-style: none; border-width: initial; width: 407px; height: 277px;"> |
//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);???//分配得來(lái)得10和20字節(jié)的區(qū)域就在堆區(qū)。
???strcpy(p1,"123456");???//123456\0放在常量區(qū),編譯器可能會(huì)將它與p3所向"123456"優(yōu)化成一個(gè)地方。
}
3.1 申請(qǐng)效率的比較:
棧:由系統(tǒng)自動(dòng)分配,速度較快。但程序員是無(wú)法控制的。
堆:是由new分配的內(nèi)存,一般速度比較慢,而且容易產(chǎn)生內(nèi)存碎片,不過(guò)用起來(lái)最方便.
另外,在WINDOWS下,最好的方式是用Virtual Alloc分配內(nèi)存,他不是在堆,也不是在棧,而是直接在進(jìn)
程的地址空間中保留一塊內(nèi)存,雖然用起來(lái)最不方便。但是速度快,也最靈活。
3.2 堆和棧中的存儲(chǔ)內(nèi)容
棧:在函數(shù)調(diào)用時(shí),第一個(gè)進(jìn)棧的是主函數(shù)中后的下一條指令(函數(shù)調(diào)用語(yǔ)句的下一條可執(zhí)行語(yǔ)句)的
地址,然后是函數(shù)的各個(gè)參數(shù),在大多數(shù)的C編譯器中,參數(shù)是由右往左入棧的,然后是函數(shù)中的局部變
量。注意靜態(tài)變量是不入棧的。
當(dāng)本次函數(shù)調(diào)用結(jié)束后,局部變量先出棧,然后是參數(shù),最后棧頂指針指向最開(kāi)始存的地址,也就是主
函數(shù)中的下一條指令,程序由該點(diǎn)繼續(xù)運(yùn)行。
堆:一般是在堆的頭部用一個(gè)字節(jié)存放堆的大小。堆中的具體內(nèi)容由程序員安排。
3.3 存取效率的比較
char s1[]="aaaaaaaaaaaaaaa";
char *s2="bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在運(yùn)行時(shí)刻賦值的;
而bbbbbbbbbbb是在編譯時(shí)就確定的;
但是,在以后的存取中,在棧上的數(shù)組比指針?biāo)赶虻淖址?例如堆)快。
總結(jié)
以上是生活随笔為你收集整理的栈大小和内存分部问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: C语言申请内存时堆栈大小限制
- 下一篇: 如何在vs2010中修改栈的大小