日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Java中的棧,堆,方法區(qū)和常量池

 Levy_X 2017-07-14

 要說Java中的棧,堆,方法區(qū)和常量池就要提到HotSpot,HotSpot是Sun JDK 和 Open JDK中所帶的虛擬機(jī)。   (Sun JDK 和 Open JDK除了注釋不同,代碼實(shí)現(xiàn)基本上是一樣的)

以下說的內(nèi)容都是圍繞HotSpot。

 

Stack(棧):分為VM Stack(虛擬機(jī)棧)和Native Method Stack(本地方法棧),不過HotSpot虛擬機(jī)直接把本地方法棧和虛擬機(jī)棧合二為一了。 

                  虛擬機(jī)棧: 線程私有的, 描述的是Java方法執(zhí)行的內(nèi)存模型,方法調(diào)用的同時(shí)創(chuàng)建一個(gè)棧幀(儲(chǔ)存局部變量表,操作數(shù)棧,方法出口等等),每個(gè)方法的調(diào)用直到執(zhí)行完成對應(yīng)的是棧幀在虛擬機(jī)中入棧和出棧的過程。                              

局部變量表(通常說的棧其實(shí)是棧里面的局部變量表):存放基本數(shù)據(jù)類型變量和對象的引用(所需內(nèi)存在編譯時(shí)期完成分配,方法運(yùn)行時(shí)期不改變局部變量表大小,四個(gè)字節(jié)占用一個(gè)局部變量空間)

 --------棧中的數(shù)據(jù)可以共享:

             int a = 3; 
             int b = 3; 
   編譯器先處理int a = 3;首先它會(huì)在棧中創(chuàng)建一個(gè)變量為a的引用,然后查找棧中是否有3這個(gè)值,如果沒找到,就將3存放 進(jìn)來,然后將a指向3。接著  處理int b = 3;在創(chuàng)建完b的引用變量后,因?yàn)樵跅V幸呀?jīng)有3這個(gè)值,便將b直接指向3。這樣,就出現(xiàn)了a與b同時(shí)均指向3的情況。這時(shí),如果再令  a=4;那么編譯器會(huì)重新搜索棧中是否有4值,如果沒有,則將4存放進(jìn)來,并令a指向4;如果已經(jīng)有了,則直接將a指向這個(gè)地址。因此a值的改變不  會(huì)影響到b的值。要注意這種數(shù)據(jù)的共享與兩個(gè)對象的引用同時(shí)指向一個(gè)對象的這種共享是不同的,因?yàn)檫@種情況a的修改并不會(huì)影響到b, 它是由編譯  器完成的,它有利于節(jié)省空間。而一個(gè)對象引用變量修改了這個(gè)對象的內(nèi)部狀態(tài),會(huì)影響到另一個(gè)對象引用變量。 

包裝類數(shù)據(jù),如Integer, String, Double等將相應(yīng)的基本數(shù)據(jù)類型包裝起來的類。這些類數(shù)據(jù)全部存在于堆中,Java用new()語句來顯示地告訴編譯器,在運(yùn)行時(shí)才根據(jù)需要?jiǎng)討B(tài)創(chuàng)建,因此比較靈活,但缺點(diǎn)是要占用更多的時(shí)間。

==比較的是對象的地址,也就是是否是同一個(gè)對象;

equal比較的是對象的值。

int 變?yōu)镮nteger 時(shí)  如果值在-128~127之間  則不會(huì)創(chuàng)建新的integer對象 儲(chǔ)存常量池中,這么做的目的是提高效率----->記得在別的地方看過不知道對不對


Java代碼  
public class Test {    
    public static void main(String[] args)    
    {  int a1=1;  
        int b1=1;  
        int c1=2;  
        int d1=a1 b1;  
        Integer a = 1;    
        Integer b = 2;    
        Integer c = 3;    
        Integer d = 3;    
        Integer e = 321;    
        Integer f = 321;    
        Long g = 3L;    
        System.out.println(a1==b1);   //true  結(jié)果1    
        System.out.println(c1==d1);   //true  結(jié)果2  
        System.out.println(c==d);   //true  結(jié)果3     
        System.out.println(e==f);   //false  結(jié)果4       
    }    
}    
 分析:結(jié)果1:a1==b1如上面所述,會(huì)在棧 中開辟存儲(chǔ)空間存放數(shù)據(jù)。
          結(jié)果2:首先它會(huì)在棧 中創(chuàng)建一個(gè)變量為c1的引用,然后查找有沒有字面值為2的地址,沒找到,就開辟一個(gè)存放2這個(gè)字面值的地址,然后將c1指向2的地址,d1為兩個(gè)字面值相加也為2, 由于在棧中已經(jīng)有2這個(gè)字面值,便將d1直接指向2的地址。這樣,就出現(xiàn)了c1與d1同時(shí)均指向3的情況。
 
        在分析下面結(jié)果以前讓我們先對Java自動(dòng)拆箱和裝箱做個(gè)了結(jié):在自動(dòng)裝箱時(shí),把int變成Integer的時(shí)候,是有規(guī)則的,當(dāng)你的int的值在-128-IntegerCache.high(127) 時(shí),返回的不是一個(gè)新new出來的Integer對象,而是一個(gè)已經(jīng)緩存在堆 中的Integer對象,(我們可以這樣理解,系統(tǒng)已經(jīng)把-128到127之 間的Integer緩存到一個(gè)Integer數(shù)組中去了,如果你要把一個(gè)int變成一個(gè)Integer對象,首先去緩存中找,找到的話直接返回引用給你就 行了,不必再新new一個(gè)),如果不在-128-IntegerCache.high(127) 時(shí)會(huì)返回一個(gè)新new出來的Integer對象。
 
         結(jié)果3:由于3是在范圍內(nèi)所以是從緩存中取數(shù)據(jù)的,c和d指向同一個(gè)對象,結(jié)果為true;
         結(jié)果4:由于321不是在范圍內(nèi)所以不是從緩存中取數(shù)據(jù)的而是單獨(dú)有new對象,e和f并沒有指向同一個(gè)對象,結(jié)果為false;

JAVA堆:

Java堆是被所有線程共享的一塊區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建 ,此內(nèi)存的唯一目的就是存放對象實(shí)例和數(shù)組   GC 管理的主要區(qū)域。

分為新生代(Eden Survivor Survivor8:1:1)和老年代

Java堆可以處于物理上不連續(xù)的內(nèi)存空間中,只要邏輯連續(xù)即可

關(guān)于對象的創(chuàng)建請參考:http://note.youdao.com/yws/public/redirect/share?id=5177014ee5ad1ac3f0af9fdab3b011a3&type=false
關(guān)于GC回收請參考:http://note.youdao.com/yws/public/redirect/share?id=96928e82082b4dec8831e5099769172b&type=false

 

方法區(qū):

            不等價(jià)于永久代hotspot用永久代實(shí)現(xiàn)方法區(qū)(在jdk1.7的HotSpot中 已經(jīng)把原本放在永久代中的字符串常量池移出
              與堆一樣是線程共享的一塊內(nèi)存區(qū)域。
              用于儲(chǔ)存已被虛擬機(jī)加載的信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。
             垃圾收集行為在方法區(qū)很少出現(xiàn),這塊區(qū)域回收的主要目標(biāo)是針對常量池的回收和對類型的卸載            

 

運(yùn)行時(shí)常量池:

                       方法區(qū)的一部分
                       常量池用于存放編譯期生成的各種字面量符號(hào)引用(還有翻譯出來的直接引用),這部分內(nèi)容在類加載后進(jìn)入方法區(qū)的運(yùn)行時(shí)常量池中存放。 
                       運(yùn)行時(shí)常量池相對于Class文件常量池的另一個(gè)重要特征是具備動(dòng)態(tài)性,運(yùn)行期間也可能將新的常量放入池中

             字面量:如文本字符串,聲明為final的常量值等。

                                       public stick final int i =3;

                                                    String s='abc';

                 符號(hào)引用:類和接口的全限定名 

                                          字段的名稱和描述符

                                方法的名稱和描述符

 

String 的本質(zhì)是字符數(shù)組。 
String 的標(biāo)準(zhǔn)實(shí)現(xiàn)含有4個(gè)實(shí)例變量 
                                        指向字符數(shù)組的引用       
                                        int類型    偏移量
                                        int類型    字符串的長度
                                        int類型     散列值

public class String{
      private char[]value;
      private int offset;
      private int count;
      private int hash;
...
}

一個(gè)String對象總共使用40字節(jié)(16字節(jié)對象本身開銷 8字節(jié)的引用 三個(gè)int類型(12字節(jié)) 4字節(jié)(填充字節(jié))),因?yàn)镾tring的char數(shù)組常常是在多個(gè)字符串之間共享的,因此String對象是不可變的

String是一個(gè)特殊的包裝類數(shù)據(jù)。即可以用String str = new String('abc');的形式來創(chuàng)建,也可以用String str = 'abc';的形式來創(chuàng)建

String str = 'abc'創(chuàng)建對象的過程
1 首先在常量池中查找是否存在內(nèi)容為'abc'字符串對象
2 如果不存在則在常量池中創(chuàng)建'abc',并讓str引用該對象
3 如果存在則直接讓str引用該對象


至 于'abc'是怎么保存,保存在哪?常量池屬于類信息的一部分,而類信息反映到JVM內(nèi)存模型中是對應(yīng)存在于JVM內(nèi)存模型的方法區(qū),也就是說這個(gè)類信息 中的常量池概念是存在于在方法區(qū)中,而方法區(qū)是在JVM內(nèi)存模型中的堆中由JVM來分配的,所以'abc'可以說存在于堆中(而有些資料,為了把方法區(qū)的 堆區(qū)別于JVM的堆,把方法區(qū)稱為棧)。一般這種情況下,'abc'在編譯時(shí)就被寫入字節(jié)碼中,所以class被加載時(shí),JVM就為'abc'在常量池中 分配內(nèi)存,所以和靜態(tài)區(qū)差不多。
4(2)String str = new String('abc')創(chuàng)建實(shí)例的過程
1 首先在堆中(不是常量池)創(chuàng)建一個(gè)指定的對象'abc',并讓str引用指向該對象
2 在字符串常量池中查看,是否存在內(nèi)容為'abc'字符串對象
3 若存在,則將new出來的字符串對象與字符串常量池中的對象聯(lián)系起來
4 若不存在,則在字符串常量池中創(chuàng)建一個(gè)內(nèi)容為'abc'的字符串對象,并將堆中的對象與之聯(lián)系起來

String str1 = 'abc'; String str2 = 'ab' 'c'; str1==str2是ture
是因?yàn)镾tring str2 = 'ab' 'c'會(huì)查找常量池中時(shí)候存在內(nèi)容為'abc'字符串對象,如存在則直接讓str2引用該對象,顯然String str1 = 'abc'的時(shí)候,上面說了,會(huì)在常量池中創(chuàng)建'abc'對象,所以str1引用該對象,str2也引用該對象,所以str1==str2
String str1 = 'abc'; String str2 = 'ab'; String str3 = str2 'c'; str1==str3是false                ---------//可參考Java編程思想第四版P284,285
是因?yàn)镾tring str3 = str2 'c'涉及到變量(不全是常量)的相加,所以會(huì)生成新的對象,其內(nèi)部實(shí)現(xiàn)是先new一個(gè)StringBuilder,然后 append(str2),append('c');然后讓str3引用toString()返回的對象

 

 

 

    String s = new String(“abc”); 產(chǎn)生幾個(gè)對象?

    一個(gè)或兩個(gè),如果常量池中原來沒有 ”abc”, 就是兩個(gè)(參考棧中的數(shù)據(jù)共享)。

 



    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多