java解惑之jvm內(nèi)存區(qū)域和類加載機制

前言

本文不會深入原理去講解,而是通過具體的場景(代碼)來理解java的內(nèi)存區(qū)域和類加載機制

java內(nèi)存區(qū)域劃分

從jvm角度看芳绩,分為堆掀亥,棧,方法區(qū)示括,本地方法棧铺浇,程序計數(shù)器


1.png

從操作系統(tǒng)角度看痢畜,分為堆垛膝,棧,數(shù)據(jù)段丁稀,代碼段

程序計數(shù)器
線程私有吼拥,指示的是當前線程字節(jié)碼執(zhí)行到的位置

虛擬機棧
線程私有,描述的是java方法執(zhí)行的內(nèi)存模型线衫,每一個方法從執(zhí)行到結(jié)束凿可,都對應一個方法棧幀的入棧和出棧,方法中的局部變量就存儲在棧中授账,當然指的是基本類型和引用類型的引用枯跑,實例還是存放在堆中
棧是一塊連續(xù)的內(nèi)存區(qū)域,大小由操作系統(tǒng)決定白热,不會產(chǎn)生碎片

本地方法棧
和虛擬機棧的作用類似敛助,只不過本地方法棧是為jvm使用到的Native方法服務


線程共享區(qū)域,存放著幾乎所有的實例
一塊大但是不連續(xù)的內(nèi)存區(qū)域屋确,容易產(chǎn)生碎片纳击,一般說的內(nèi)存泄漏,主要指的就這塊

方法區(qū)
線程共享區(qū)域攻臀,存儲已經(jīng)被jvm加載的類的信息焕数,常量,靜態(tài)變量刨啸,編譯器編譯后的代碼等數(shù)據(jù)
運行時常量池就是方法區(qū)的一部分堡赔,用于存放各種字面量和符號引用
字面量:基本類型的包裝類,字符串類型设联,final修飾的常量

代碼示例

public class People{
  int a = 1;
  final int b=2;
  static int c=3;
  Student s1 = new Student();
  public void XXX(){
      int d = 1;
      Student s2 = new Student();
  }
}

問a善已,b,c仑荐,d的內(nèi)存在哪里雕拼,s1,s2的內(nèi)存在哪里粘招?
記住下面幾句話啥寇。
成員變量全部存儲在堆中(包括基本數(shù)據(jù)類型,引用及引用的對象實體),因為他們屬于對象辑甜,對象都是存儲在堆中的
局部變量的基本數(shù)據(jù)類型和引用存儲于棧當中衰絮,引用的對象實體存儲在堆中。因為他們屬于方法當中的變量磷醋,生命周期會隨著方法一起結(jié)束猫牡。
常量,靜態(tài)變量(屬于類)存放在常量池
存放在堆中的有a邓线,s1和s1的實例淌友,s2的實例
存放在棧中的有d,s2
存放在方法區(qū)(常量池)的有b骇陈,c

類加載

什么是類加載

類加載指的是將.class文件的二進制數(shù)據(jù)讀取到內(nèi)存中震庭,將其放入內(nèi)存區(qū)域中的方法區(qū),然后在堆中創(chuàng)建一個Class對象你雌,這就是我們說的任何類都是Class類的一個實例的原因

什么時候進行類加載

簡單說就是類在用到的時候才會被加載器联,下面我來列舉一些情況來說明什么叫被用到

  • 創(chuàng)建類的實例
  • 調(diào)用類的靜態(tài)變量(final修飾的靜態(tài)變量除外)
  • 調(diào)用類的靜態(tài)方法
  • 反射如Class.forName(com.xxx.xxx)
類加載過程

1.類加載
類的加載是由類加載器來完成加載的
說到類加載,我們來簡單說下雙親委派機制
java自帶的3中類加載器分別是AppClassLoader婿崭,ExtClassLoader和Bootstrap
我們自己寫的類首先會調(diào)用AppClassLoader去加載自身拨拓,但它不會馬上加載,而是調(diào)用ExtClassLoader去加載氓栈,它也不會馬上加載渣磷,而是調(diào)用Bootstrap去加載,如果Bootstrap加載不了颤绕,就讓ExtClassLoader去加載幸海,還加載不了就讓AppClassLoader加載

2.類的連接
類連接有3步,分別是驗證奥务,準備物独,解析
這里我只說明一下準備階段做的工作
為類的靜態(tài)變量分配內(nèi)存并賦值默認的初始值

 public static int value=123;

在準備階段value的值是0

3.類的初始化(順序)

  • 沒有父類的情況
    類的靜態(tài)屬性
    類的靜態(tài)代碼塊
    類的非靜態(tài)屬性
    類的非靜態(tài)代碼塊
    構(gòu)造方法

  • 有父類的情況
    父類的靜態(tài)屬性
    父類的靜態(tài)代碼塊
    子類的靜態(tài)屬性
    子類的靜態(tài)代碼塊
    父類的非靜態(tài)屬性
    父類的非靜態(tài)代碼塊
    父類的構(gòu)造方法
    子類的非靜態(tài)屬性
    子類的非靜態(tài)代碼塊
    子類的構(gòu)造方法

代碼示例1
public class SingleTon {

  private static SingleTon singleTon = new SingleTon();
  public static int count1;
  public static int count2 = 0;

  private SingleTon() {
    count1++;
    count2++;
  }

  public static SingleTon getInstance() {
    return singleTon;
  }

  public static void main(String[] args) {
    SingleTon singleTon = SingleTon.getInstance();
    System.out.println("count1=" + singleTon.count1);
    System.out.println("count2=" + singleTon.count2);
  }
}

結(jié)果輸出

count1=1
count2=0

結(jié)果分析
1.調(diào)用類的靜態(tài)方法會觸發(fā)類的加載
2.在準備階段為靜態(tài)變量分配內(nèi)存并賦值默認初始值
singleTon=null;
count1=0;
count2=0;
3.初始化操作(賦值操作),初始化是從上到下依次執(zhí)行的
先調(diào)用new操作氯葬,count1=1挡篓,count2=1
count1沒有賦值操作
count2進行賦值操作

修改代碼如下

public class SingleTon {

  public static int count1;
  public static int count2 = 0;
  private static SingleTon singleTon = new SingleTon();


private SingleTon() {
    count1++;
    count2++;
}

public static SingleTon getInstance() {
    return singleTon;
}

public static void main(String[] args) {
    SingleTon singleTon = SingleTon.getInstance();
    System.out.println("count1=" + singleTon.count1);
    System.out.println("count2=" + singleTon.count2);
  }
}

結(jié)果輸出

count1=1
count2=1
代碼示例2
public class HelloA {

  public static int a=1;
  
  static{
    System.out.println("Static A");
  }

  {
    System.out.println("I am A class");
  }

public HelloA(int i){
    System.out.println("Hello A");
  }
}

public class HelloB  extends HelloA{
  public static int b=0;

  static{
    System.out.println("Static B");
  }

  {
    System.out.println("I am B class");
  }

  public HelloB(){
    super(1);
    System.out.println("Hello B");
  }

  public static void main(String[] args) {
    new HelloB();   
    //HelloB.a=1;
  }
}

輸出結(jié)果

Static A
Static B
I am A class
Hello A
I am B class
Hello B

結(jié)果分析
參考前面類的初始化順序

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市帚称,隨后出現(xiàn)的幾起案子官研,更是在濱河造成了極大的恐慌,老刑警劉巖闯睹,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件戏羽,死亡現(xiàn)場離奇詭異,居然都是意外死亡楼吃,警方通過查閱死者的電腦和手機始花,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門妄讯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人酷宵,你說我怎么就攤上這事亥贸。” “怎么了浇垦?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵炕置,是天一觀的道長。 經(jīng)常有香客問我男韧,道長朴摊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任煌抒,我火速辦了婚禮仍劈,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘寡壮。我一直安慰自己,他們只是感情好讹弯,可當我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布况既。 她就那樣靜靜地躺著,像睡著了一般组民。 火紅的嫁衣襯著肌膚如雪棒仍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天臭胜,我揣著相機與錄音莫其,去河邊找鬼。 笑死耸三,一個胖子當著我的面吹牛乱陡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播仪壮,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼憨颠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了积锅?” 一聲冷哼從身側(cè)響起爽彤,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎缚陷,沒想到半個月后适篙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡箫爷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年嚷节,在試婚紗的時候發(fā)現(xiàn)自己被綠了铆铆。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡丹喻,死狀恐怖薄货,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情碍论,我是刑警寧澤谅猾,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站鳍悠,受9級特大地震影響税娜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜藏研,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一敬矩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蠢挡,春花似錦弧岳、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至勤家,卻和暖如春腹尖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背伐脖。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工热幔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人讼庇。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓绎巨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親巫俺。 傳聞我的和親對象是個殘疾皇子认烁,可洞房花燭夜當晚...
    茶點故事閱讀 45,047評論 2 355

推薦閱讀更多精彩內(nèi)容