程序運(yùn)行的時(shí)候是把局部變量放在棧區(qū),而動(dòng)態(tài)變量放在堆區(qū)。請(qǐng)大家詳細(xì)解釋下這樣安排的原因是啥?可以把局部變量放在堆區(qū)嗎?為社么?謝謝 --------------------------------------------------------------- 棧區(qū)是普通的棧數(shù)據(jù)結(jié)構(gòu),遵循LIFO后進(jìn)先出的規(guī)則,局部變量安排在那里是ASM時(shí)就規(guī)定的,這樣可以在一個(gè)函數(shù)結(jié)束后平衡堆棧,操作簡(jiǎn)單,效率高 堆(動(dòng)態(tài)區(qū))在這里應(yīng)當(dāng)叫堆棧(不要和數(shù)據(jù)結(jié)構(gòu)中的堆搞混)是程序在編譯時(shí)產(chǎn)生的一塊用于產(chǎn)生動(dòng)態(tài)內(nèi)存分配使用的塊,操作比較棧要麻煩許多,在分配時(shí)要判斷最優(yōu)的地址(防止產(chǎn)生無(wú)用的內(nèi)存碎片(由于屢次的NEW和DELETE產(chǎn)生的夾在兩塊使用中內(nèi)存中的空余小內(nèi)存(不容易被分配))),分配和回收時(shí)的效率比棧低多了 --------------------------------------------------------------- 棧是系統(tǒng)提供的功能,特點(diǎn)是快速高效,缺點(diǎn)是有限制,數(shù)據(jù)不靈活;而棧是函數(shù)庫(kù)提供的功能,特點(diǎn)是靈活方便,數(shù)據(jù)適應(yīng)面廣泛,但是效率 >有一定降低。棧是系統(tǒng)數(shù)據(jù)結(jié)構(gòu),對(duì)于進(jìn)程/線程是唯一的;堆是函數(shù)庫(kù)內(nèi)部數(shù)據(jù)結(jié)構(gòu),不一定唯一。不同堆分配的內(nèi)存無(wú)法互相操作。棧空間分靜態(tài)分配和動(dòng)態(tài)分配兩種。靜態(tài)分配是編譯器完成的,比如自動(dòng)變量(auto)的分配。動(dòng)態(tài)分配由alloca函數(shù)完成。棧的動(dòng)態(tài)分配無(wú)需釋放(是自動(dòng)的),也就沒(méi)有釋放函數(shù)。為可移植>的程序起見(jiàn),棧的動(dòng)態(tài)分配操作是不被鼓勵(lì)的!堆空間的分配總是動(dòng)態(tài)的,雖然程序結(jié)束時(shí)所有的數(shù)據(jù)空間都會(huì)被釋放回系統(tǒng),但是精確的申請(qǐng)內(nèi)存/ 釋放內(nèi)存匹>配是良好程序的基本要素。 這是我對(duì)堆與棧收藏內(nèi)容~ --------------------------------------------------------------- 哦,不行的。 如果所有局部變量都在堆上分配,那么每次函數(shù)調(diào)用都要增加一次malloc和free,本來(lái)一次指針加法和一次指針加法就可以搞定的事情就一下子變得低效了不下10倍。 但問(wèn)題在于,現(xiàn)在你要調(diào)用函數(shù)了,你需要首先調(diào)用malloc,為被調(diào)函數(shù)分配存儲(chǔ)空間(或者被調(diào)函數(shù)自己調(diào)用malloc來(lái)為自己分配,都一樣),然后函數(shù)返回的時(shí)候調(diào)用free。 好了,函數(shù)調(diào)用開(kāi)始了,首先malloc被調(diào)用,但malloc也是函數(shù)啊,為了調(diào)用函數(shù),你首先要調(diào)用誰(shuí)?當(dāng)然是malloc,好,再調(diào)用malloc,但malloc也是函數(shù)啊,為了調(diào)用函數(shù),你首先要調(diào)用誰(shuí)?當(dāng)然是malloc,好,再調(diào)用malloc,…… 這就叫無(wú)限遞歸。。。。 --------------------------------------------------------------- 一般將全局變量存放在數(shù)據(jù)區(qū),局部變量存放在棧區(qū), 動(dòng)態(tài)變量存放在堆區(qū),函數(shù)代碼放在代碼區(qū)。 --------------------------------------------------------------- 堆是程序員管理的,棧是系統(tǒng)管理的. --------------------------------------------------------------- 局部變量放在棧區(qū),而動(dòng)態(tài)變量放在堆區(qū)。請(qǐng)大家詳細(xì)解釋下這樣安排的原因是啥? ---------- 局部變量是有確定生命期的,這個(gè)可以由系統(tǒng)來(lái)管理(事實(shí)也是如此),而系統(tǒng)管理的是棧,所以,局部變量在棧中; 動(dòng)態(tài)變量的生命期由程序員決定,所以要放在堆中。 (也許,注意,是也許,原始的設(shè)計(jì)的原因是為了 便于程序的設(shè)計(jì) 和 管理(否則一切事物都要程序員來(lái)解決,會(huì)累死人的)) 可以把局部變量放在堆區(qū)嗎? ----------------------- 怎么說(shuō)呢? 所有的編譯器都不可能達(dá)到這樣的效果。 如果你非要這樣,哎 ,可以自己發(fā)明一種語(yǔ)言,自己設(shè)計(jì)編譯器,要圓要扁,還不是你自己決定? 呵呵 ! --------------------------------------------------------------- Java中的內(nèi)建類(lèi)型和對(duì)象的引用也是放在棧里邊的,這也是不夠成無(wú)限遞歸的原因。 其實(shí)只要你愿意,你也可以按Java風(fēng)格寫(xiě)C++程序:每個(gè)局部變量都通過(guò)new動(dòng)態(tài)產(chǎn)生,然后變量本身自然在堆里,指向它的指針則在棧里。只是別忘了delete。 總之,不可能所有的東西都放堆里。 --------------------------------------------------------------- steedhorse(晨星) 說(shuō)的那個(gè)無(wú)限遞歸很有道理哦。。 --------------------------------------------------------------- 真是這樣的嗎?! 我怎么覺(jué)得大家都沒(méi)說(shuō)到點(diǎn)子上,甚至連堆和棧是什么都沒(méi)能講清楚。 看下邊的代碼 class Test { public static void main(String[] args) { Obj obj = new Obj(); obj.do(); } } class Obj { public do() { int i = 0; } } 思考題: 1、i 做為 obj 的一個(gè)成員,是不是在堆中? 2、當(dāng)主線程執(zhí)行 obj.do() 時(shí),i 是不是在主線程的棧上? :) --------------------------------------------------------------- (1)obj這個(gè)對(duì)象在堆中,但棧中保存著它的引用,否則如果沒(méi)有東西引用它,這個(gè)對(duì)象會(huì)被垃圾回收器收掉的。 (2)i是在棧上。 關(guān)于函數(shù)棧,學(xué)過(guò)編譯原理會(huì)更清楚一些。 --------------------------------------------------------------- 任何一門(mén)語(yǔ)言或者編譯器,如果想把所有的局部變量(包括局部產(chǎn)生的對(duì)象和這些對(duì)象的引用、指針等、別名等)都放到堆上去,就只能在每次函數(shù)調(diào)用前首先分配堆空間。 --------------------------------------------------------------- 我是說(shuō):假如要實(shí)現(xiàn)樓主的愿望:“函數(shù)調(diào)用時(shí)所有的局部東西都放堆里,半點(diǎn)也不留在棧里”,那么函數(shù)調(diào)用就必然造成無(wú)限遞歸。 并非說(shuō)平時(shí)我們的函數(shù)調(diào)用都會(huì)造成無(wú)限遞歸。一般的編譯器都把局部變量(或者至少它們的引用)放在棧里,當(dāng)然不會(huì)造成無(wú)限遞歸。 --------------------------------------------------------------- 當(dāng)然,如果你說(shuō):“假如所有的函數(shù)都用堆,只有malloc不用堆”,那malloc用啥?只用棧?全部函數(shù)都被不用棧,就單單為了malloc這一個(gè)函數(shù)(當(dāng)然,還有其它幾個(gè))來(lái)開(kāi)辟一個(gè)棧并開(kāi)發(fā)一套棧式調(diào)用算法?那不是很蹩腳么? 那么C編譯器在編譯運(yùn)行時(shí)庫(kù)的時(shí)候,每次編譯到一個(gè)函數(shù),都得檢查一下,這個(gè)函數(shù)的名字是否叫做“malloc”(或者“realloc”等幾個(gè)),如果是就做特殊處理,如過(guò)不叫malloc就做一般處理? 不用往下說(shuō)了,這樣的編譯器聽(tīng)起來(lái)不覺(jué)的別扭嗎? --------------------------------------------------------------- 可能我說(shuō)得太多了吧。其實(shí)問(wèn)題本來(lái)很簡(jiǎn)單,關(guān)鍵就在于:如果你想放棄使用棧,而統(tǒng)一使用堆來(lái)進(jìn)行一切函數(shù)調(diào)用,那么就不能再使用簡(jiǎn)單的棧指針加減來(lái)進(jìn)行棧內(nèi)存的分配,而必須在每個(gè)函數(shù)被調(diào)用前為函數(shù)動(dòng)態(tài)分配保存局部變量的空間,但分配空間的函數(shù)也是函數(shù),它也得首先調(diào)用它自己來(lái)分配空間,于是形成了無(wú)限遞歸。 --------------------------------------------------------------- 局部變量不是全部放于棧的,關(guān)鍵看自己如何定義。 而關(guān)于堆和棧,真的是各有所用,各有各的特點(diǎn)。雖然大家都是位于RAM中。 對(duì)于棧,cpu經(jīng)由其stack pointer 提供直接支援。編譯器必須能夠完全掌握變量(對(duì)象)的大小和存活時(shí)間。優(yōu)點(diǎn)是存取較快,不需要自行回收空間。 而對(duì)于堆,編譯器不需要知道變量(對(duì)象)的大小及其存活多久。相比棧,存取較慢,空間需要自行釋放,否則會(huì)造成臭名昭著的“Menory leading”。 其實(shí),變量的存儲(chǔ)空間除了棧和堆,還有cpu暫存器(Registers)、靜態(tài)儲(chǔ)存空間(Static storage)、常量?jī)?chǔ)存空間(Constant storage)、Non RAM儲(chǔ)存空間。它們都是各有各的用途,各有各的特點(diǎn)。 --------------------------------------------------------------- 呵呵,不好意思,把大家搞糊涂了。一些話說(shuō)的不嚴(yán)密,尤其這句容易誤導(dǎo): “如果你想放棄使用棧,而統(tǒng)一使用堆來(lái)進(jìn)行一切函數(shù)調(diào)用,那么就不能再使用簡(jiǎn)單的棧指針加減來(lái)進(jìn)行棧內(nèi)存的分配,而必須在每個(gè)函數(shù)被調(diào)用前為函數(shù)動(dòng)態(tài)分配保存局部變量的空間,……” 應(yīng)該改成: |
|
來(lái)自: 昵稱2144770 > 《計(jì)算機(jī)》