由于位于處理器cpu的內(nèi)部,所以其是最快的存儲(chǔ)區(qū),然而寄存器的空間極其珍貴有限,所以程序開(kāi)發(fā)者無(wú)法直接控制寄存器空間的分配,它的分配工作是由編譯器自行分配的.
位于通用RAM中,即內(nèi)存中。它可以通過(guò)”堆棧指針”從cpu那里獲取支持,通過(guò)操作”堆棧指針”的上下移動(dòng)來(lái)實(shí)現(xiàn)堆棧區(qū)中對(duì)內(nèi)存的申請(qǐng)和釋放.堆棧指針若向下移動(dòng),則分配新的內(nèi)存;若向上移動(dòng),則釋放那些內(nèi)存。這是一種快速有效的分配存儲(chǔ)方法,速度僅次于寄存器.
創(chuàng)建程序時(shí)候,JAVA編譯器必須知道存儲(chǔ)在堆棧內(nèi)所有數(shù)據(jù)的確切大小和生命周期,因?yàn)樗仨毶上鄳?yīng)的代碼,以便上下移動(dòng)堆棧指針。這一約束限制了程序的靈活性,所以雖然某些JAVA數(shù)據(jù)存儲(chǔ)在堆棧中——特別是對(duì)象引用,但是JAVA對(duì)象不存儲(chǔ)其中.
跟堆棧區(qū)一樣也存在于RAM中,用于存放所有的JAVA對(duì)象。堆不同于堆棧的好處是:編譯器不需要知道要從堆里分配多少存儲(chǔ)區(qū)域,也不必知道存儲(chǔ)的數(shù)據(jù)在堆里存活多長(zhǎng)時(shí)間。因此,在堆里分配存儲(chǔ)有很大的靈活性。當(dāng)你需要?jiǎng)?chuàng)建一個(gè)對(duì)象的時(shí)候,只需要new寫(xiě)一行簡(jiǎn)單的代碼,當(dāng)執(zhí)行這行代碼時(shí),會(huì)自動(dòng)在堆里進(jìn)行存儲(chǔ)分配。當(dāng)然,為這種靈活性必須要付出相應(yīng)的代碼。用堆進(jìn)行存儲(chǔ)分配比用堆棧進(jìn)行存儲(chǔ)存儲(chǔ)需要更多的時(shí)間.
存儲(chǔ)用static修飾的成員變量或方法.雖然static關(guān)鍵字可以用來(lái)標(biāo)識(shí)一個(gè)對(duì)象是靜態(tài)的,但JAVA對(duì)象本身不會(huì)被存放在靜態(tài)存儲(chǔ)空間里,而是存儲(chǔ)在堆內(nèi)存區(qū).
常量(字符串常量和基本類(lèi)型常量)通常直接存儲(chǔ)在程序代碼內(nèi)部(常量池)。這樣做是安全的,因?yàn)樗鼈兊闹翟诔跏蓟瘯r(shí)就已經(jīng)被確定,并不會(huì)被改變。常量池在java用于保存在編譯期已確定的,已編譯的class文件中的一份數(shù)據(jù)。它包括了關(guān)于類(lèi),方法,接口等中的常量,也包括字符串常量,如String s = “abc”這種字面量方式.
如果數(shù)據(jù)完全存活于程序之外,那么它可以不受程序的任何控制,在程序沒(méi)有運(yùn)行時(shí)也可以存在.
這是一個(gè)關(guān)于堆與棧關(guān)系的引用說(shuō)明
堆:堆是heap,是所謂的動(dòng)態(tài)內(nèi)存,其中的內(nèi)存在不需要時(shí)可以回收,以分配給新的內(nèi)存請(qǐng)求,其內(nèi)存中的數(shù)據(jù)是無(wú)序的,即先分配的和隨后分配的內(nèi)存并沒(méi)有什么必然的位置關(guān)系,釋放時(shí)也可以沒(méi)有先后順序。一般由使用者自由分配,在C語(yǔ)言中malloc分配的就是堆,需要手動(dòng)釋放。 堆棧:就是stack。實(shí)際上是只有一個(gè)出入口的隊(duì)列,即后進(jìn)先出(frist in , last out),先分配的內(nèi)存必定后釋放。一般由,由系統(tǒng)自動(dòng)分配,存放函數(shù)的參數(shù)值,局部變量等,自動(dòng)清除。 還有,堆是全局的,堆棧是每個(gè)函數(shù)進(jìn)入的時(shí)候分一小塊,函數(shù)返回的時(shí)候就釋放了,靜態(tài)和全局變量,new得到的變量,都放在堆中,局部變量放在堆棧中,所以函數(shù)返回,局部變量就全沒(méi)了。 JAVA中的基本類(lèi)型,其實(shí)需要特殊對(duì)待。因?yàn)椋贘AVA中,通過(guò)new創(chuàng)建的對(duì)象存儲(chǔ)在“堆”中,所以用new 創(chuàng)建一個(gè)小的、簡(jiǎn)單的變量,如基本類(lèi)型等,往往不是很有效。因此,在JAVA中,對(duì)于這些類(lèi)型,采用了與C、C++相同的方法。也就是說(shuō),不用new 來(lái)創(chuàng)建,而是創(chuàng)建一個(gè)并非是“引用”的“自動(dòng)”變量。這個(gè)變量擁有它的“值”,并置于堆棧中,因此更高效。 實(shí)際上類(lèi)的實(shí)例方法在內(nèi)存中是只有一份,不過(guò)肯定不會(huì)是第一個(gè)對(duì)象中,如果是第一個(gè)對(duì)象的話,那么當(dāng)?shù)谝粋€(gè)對(duì)象被銷(xiāo)毀的時(shí)候,那么后面的對(duì)象就永遠(yuǎn)無(wú)法調(diào)用了。 類(lèi)的實(shí)例方法存在一個(gè)專(zhuān)門(mén)的區(qū)叫方法區(qū)(method area),事實(shí)上類(lèi)剛裝載的時(shí)候就被裝載好了,不過(guò)它們?cè)凇彼摺?只是這些方法必須當(dāng)有對(duì)象產(chǎn)生的時(shí)候才會(huì)”蘇醒”.(比如,一個(gè)輸出類(lèi)的成員變量的方法,如果連對(duì)象都沒(méi)有,何來(lái)的輸出成員變量).所以,方法在裝載的時(shí)候就有了,但是不可用,因?yàn)樗鼪](méi)有指象任何一個(gè)對(duì)象. 而靜態(tài)的又不一樣了,靜態(tài)的東西存在靜態(tài)存儲(chǔ)(static storage)區(qū),他們和類(lèi)是一個(gè)等級(jí)的,就是說(shuō)只要類(lèi)被裝載,它們就可以直接用.(用類(lèi)名來(lái)調(diào)用).他們不依賴(lài)與任何對(duì)象,所以也不能輸出任何對(duì)象的成員屬性.(除非成員屬性也是靜態(tài)的). 每個(gè)對(duì)象在new的時(shí)候都會(huì)在堆區(qū)中開(kāi)辟內(nèi)存,用來(lái)保存對(duì)象的屬性和方法.(實(shí)際上方法保存的只是方法區(qū)的引用,如果保存的是方法本身,那么試想一下,有多少個(gè)對(duì)象就得有多少個(gè)方法,那么又和第一點(diǎn)中”實(shí)例方法在內(nèi)存中只有一份拷貝”相矛盾了)。
假設(shè)我們定義了兩個(gè)局部變量(注意局部變量和方法形參才保存在棧中,成員變量是保存在堆中,不要混淆了) int s1=20;int s2=20;編譯器工作流程如下:
在棧中申請(qǐng)一個(gè)名為”s1”的存儲(chǔ)空間,然后查看棧中是否存放著一個(gè)”20”的值;如果棧中不存在”20”的值,就向棧中添加一個(gè)”20”的值,然后讓s1等于這個(gè)值.如果棧中存在”20”的值,就讓s1等于這個(gè)值而不用在棧中重新加入一個(gè)”20”的值.完成了對(duì)s1的數(shù)據(jù)分配后,由于s2=20,所以就不用再為s2在棧中重新分配”20”這個(gè)值了,這樣就實(shí)現(xiàn)了數(shù)據(jù)共享,節(jié)省了內(nèi)存空間.新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注