1. 程式人生 > >淺析Java的jvm上的內存位置的分配

淺析Java的jvm上的內存位置的分配

結束 nio 局部變量 指令 ack 沒有 動態鏈接 情況下 基本數據類型

淺析Javajvm上的內存位置的分配

1.Java的內存區域簡介

1>程序計數器:

一小塊的內存空間,每個線程都有一個獨立的計數器,線程私有;作用:作為當前線程代碼行行號指示器,這個值可以選取下一條需要執行的字節碼指令,例如分支,循環等,每創建一根線程會相應的產生一個程序計數器

2>棧

線程私有,用於存放局部變量,保存基本數據類型的值,操作數棧(保存著計算過程的中間結果),動態鏈接,方法入口和出口等信息;局部變量表中保存著函數的參數和局部變量,當調用結束以後,棧幀銷毀,局部變量表也隨之銷毀 ,局部變量表可以復用過期的局部變量的槽位,棧幀彈棧有兩種情況,return和異常,棧為先進後出的結構,有深度所以會溢出,上述所說的操作數棧和局部變量表是都是棧幀的組成部分,棧幀至少有三部分組成,操作數棧,局部變量表,幀數據區。

3>堆

線程共享;虛擬機所管理內存區域最大的一塊地方,存放對象實例和數組,註意創建出來的對象只包含屬於各自的成員變量(對象的屬性),並不包括成員方法。因為同一個類的對象擁有各自的成員變量,存儲在各自的堆中,但是他們共享該類的方法,並不是每創建一個對象就把成員方法復制一次。

4>本方法地棧

為native服務(c/c++/fortran編寫),行為和棧基本類似

5>方法區

線程共享,用於存放虛擬機加載的類信息,方法區中有常量池存放著常量(字面量),靜態變量等數據

6>運行時常量池

方法區的一部分,用於存放編譯期生成的各種字面量和符號引用(符號引用:類和接口的全限定名,字段的名稱和描述符,方法的名稱和描述符)

7>直接內存

直接內存不是java規範中的內存,也不隸屬於堆,大小不受堆大小的限制,直接內存是指向java堆外,直接向系統申請內存空間,通常情況下直接內存的效率會優於java堆,直接內存和java堆的總和依然受限於操作系統能給出的最大內存限制。在nio(見後續nio)中是通過堆中的DirectByteBuffer實現對直接內存進行訪問,能在一些場景中顯著的提高性能

2.實例1:

package StaticTest;

public class Test { //加載在方法區

public static int i0=10; //方法區

public final int i=100;//常量池

public static void main(String[] args) {

int i1=10; //棧

int i2=10;//棧

String str1="abc"; //棧指向常量池

String str2="abc"; //str2棧指向常量池

String str3=str1+str2;//棧指向堆

String str4="abcabc";棧指向常量池

String str5=new String("abc"); 棧指向堆

int i3=i1+i2; 棧

int i4=20; 棧

System.out.println(i0==i1);

System.out.println(i1==i2);

System.out.println(i3==i4);

System.out.println(str1==str2);

System.out.println(str3==str4);

System.out.println(str1==str5);

}

}true true true true false false

分析:首先會將類加載到方法區,然後放置一個class對象在堆區作為引用,main方法自身在方法區, i0在方法區等,基本數據類型i1,i2,以及與使用了常量池技術的字符串str1,str2,str4的引用在棧中,棧中的數據是可以共享的,所以i1,i2是指向同一個數字,對於棧中存放的基本類型數據,假如不存在那麽就創建,假如存在那麽就指向存在的地址,基本類型數據的運算也是在棧中進行(操作數棧),對於包裝類(不論有沒有new)與基本類型數據的==及各種運算,java會自動進行拆箱操作轉換為相應的基本類型數據,指向相應的棧中,包裝類(不論有沒有new)與包裝類(不論有沒有new)的各種運算也會相應的轉換為基本類型數據後進行相應的運算(==除外),new的實例在堆中,new只是創建各自的成員變量(不包含靜態部分),不包含方法體,被final修飾的數據在常量池中,對於String和包裝類都實現了常量池技術,String會先檢查常量池中是否存在,假如不存在那麽會創建,存在就指向存在的地址,String的加法是在堆中進行的,字符串的+底層是基於StringBuilder(見後續的java的字符處理)。在jdk6.0中String的常量池在方法區中,在jdk7.0中的String的常量池在堆中,綜上所訴:new之後會創建各自的成員變量;而對於方法區中(這些是通過放入堆中的class對象來實現調用的)的靜態成員變量及方法自身只會存在一份,對於常量池中的常量也只存在一份,且設定初始值後不能改變,對於Byte及小於-128~127之間的Integer以及Character的包裝類以及String在沒有new的前提下是直接指向常量池的同一個地址,new過之後會相應的進入堆中,對於其他的包裝類,會相應的進入到堆中。常量池中的字面量和棧中的基本類型數據有區別,棧中的基本類型數據會相應的自動轉換,常量池中的字面量不會自動轉換,例如Double d1=123456d;後續要加d,不加d就會編譯錯誤等

技術分享圖片

實例和對象的區別 :new或者反射出來的實例(newInstance等)叫實例,new出來或者反射出來的實例的引用叫對象;

淺析Java的jvm上的內存位置的分配