Java內(nèi)存圖以及堆、棧灌诅、常量區(qū)芳来、靜態(tài)區(qū)、方法區(qū)的區(qū)別


如果是一個類里面的靜態(tài)成員變量和靜態(tài)成員方法猜拾,它是存儲在方法區(qū)的即舌,靜態(tài)成員變量是在方法區(qū)的靜態(tài)域里面,而靜態(tài)成員方法是在方法區(qū)的class二進制信息里面(.class文件和方法區(qū)里面的二進制信息不一樣挎袜,讀取.class文件按照虛擬機需要的格式存儲在方法區(qū)顽聂。這種格式包括數(shù)據(jù)結構方面)肥惭,靜態(tài)成員和靜態(tài)成員方法使用時不用創(chuàng)建對象,即類加載初始化后就可以使用芜飘,并且是線程共享的务豺。

通過圖中分析,很多問題也能夠迎刃而解嗦明,比如不同線程調(diào)用方法為什么是線程安全的笼沥。局部變量存儲在哪兒里(棧中),成員變量存儲在哪兒里(靜態(tài)成員變量存儲在方法區(qū)娶牌,非靜態(tài)成員變量存儲在堆區(qū))奔浅,為什么局部變量不能夠static修飾等(局部變量存儲在棧區(qū),在方法調(diào)用時不能夠自動初始化必須由程序員手動初始化诗良,否則會報錯托猩,歸根結底是由于static變量和局部變量存儲的位置不一樣单寂。)。

Java內(nèi)存空間個人理解

堆:堆主要存放Java在運行過程中new出來的對象,凡是通過new生成的對象都存放在堆中千劈,對于堆中的對象生命周期的管理由Java虛擬機的垃圾回收機制GC進行回收和統(tǒng)一管理皆刺。類的非靜態(tài)成員變量也放在堆區(qū)休讳,其中基本數(shù)據(jù)類型是直接保存值颠黎,而復雜類型是保存指向?qū)ο蟮囊茫庆o態(tài)成員變量在類的實例化時開辟空間并且初始化总处。所以你要知道類的幾個時機狈惫,加載-連接-初始化-實例化。

棧:棧主要存放在運行期間用到的一些局部變量(基本數(shù)據(jù)類型的變量)或者是指向其他對象的一些引用鹦马,因為方法執(zhí)行時胧谈,被分配的內(nèi)存就在棧中,所以當然存儲的局部變量就在棧中咯荸频。當一段代碼或者一個方法調(diào)用完畢后菱肖,棧中為這段代碼所提供的基本數(shù)據(jù)類型或者對象的引用立即被釋放;

常量池:常量池是方法區(qū)的一部分內(nèi)存旭从。常量池在編譯期間就將一部分數(shù)據(jù)存放于該區(qū)域稳强,包含基本數(shù)據(jù)類型如int、long等以final聲明的常量值遇绞,和String字符串键袱、特別注意的是對于方法運行期位于棧中的局部變量String常量的值可以通過 String.intern()方法將該值置入到常量池中燎窘。

靜態(tài)域:位于方法區(qū)的一塊內(nèi)存摹闽。存放類中以static聲明的靜態(tài)成員變量

方法區(qū):是各個線程共享的內(nèi)存區(qū)域,它用于存儲class二進制文件褐健,包含了虛擬機加載的類信息付鹿、常量澜汤、靜態(tài)變量、即時編譯后的代碼等數(shù)據(jù)舵匾。它有個名字叫做Non-Heap(非堆)俊抵,目的是與Java堆區(qū)分開。

需要特別注意的是:

方法區(qū)是線程安全的坐梯。由于所有的線程都共享方法區(qū)徽诲,所以,方法區(qū)里的數(shù)據(jù)訪問必須被設計成線程安全的吵血。例如谎替,假如同時有兩個線程都企圖訪問方法區(qū)中的同一個類,而這個類還沒有被裝入JVM蹋辅,那么只允許一個線程去裝載它钱贯,而其它線程必須等待 !

最后總結起來就是:

棧:為即時調(diào)用的方法開辟空間侦另,存儲局部變量值(基本數(shù)據(jù)類型)秩命,局部變量引用。注意:局部變量必須手動初始化褒傅。

堆:存放引用類型的對象弃锐,即new出來的對象、數(shù)組值樊卓、類的非靜態(tài)成員變量值(基本數(shù)據(jù)類型)拿愧、非靜態(tài)成員變量引用。其中非靜態(tài)成員變量在實例化時開辟空間初始化值碌尔。更具體點浇辜,個人感覺非靜態(tài)成員變量是放在堆的對象中。

方法區(qū):存放class二進制文件唾戚。包含類信息柳洋、靜態(tài)變量,常量池(String字符串和final修飾的常量值等)叹坦,類的版本號等基本信息熊镣。因為是共享的區(qū)域,所以如果靜態(tài)成員變量的值或者常量值(String類型的值能夠非修改募书,具體請查看博客)被修改了直接就會反應到其它類的對象中绪囱。

成員變量與局部變量總結:

一:在方法中聲明的變,即該變量是局部變量莹捡,每當程序調(diào)用方法時鬼吵,系統(tǒng)都會為該方法建立一個方法棧,其所在方法中聲明的變量就放在方法棧中篮赢,當方法結束系統(tǒng)會釋放方法棧齿椅,其對應在該方法中聲明的變量隨著棧的銷毀而結束琉挖,這就局部變量只能在方法中有效的原因<1>在方法中生明的變量可以是基本類型的變量,也可以是引用類型的變量涣脚,(1)當聲明是基本類型的變量的時示辈,其變量名及值(變量名及值是兩個概念)是放在方法棧中(2)當聲明的是引用變量時,所聲明的變量(該變量實際上是在方法中存儲的是內(nèi)存地址值)是放在方法的棧中遣蚀,該變量所指向的對象是放在堆類存中的》》》二:在類中聲明的變量是成員變量矾麻,也叫全局變量,放在堆中的芭梯,<1>同樣在類中聲明的變量即可是基本類型的變量 也可是引用類型的變量(1)當聲明的是基本類型的變量其變量名及其只時放在堆類存中的射富,(2)引用類型時,其聲明的變量仍然會存儲一個內(nèi)存地址值粥帚,該內(nèi)存地址值指向所引用的對象

下面給大家看一個Java代碼例子:

聲明一個類:

public class A {

? ? public final String tempString="world";//這里可以把final去掉胰耗,結果等同!芒涡!

? ? public final char[] charArray="Hello".toCharArray();

? ? public char[] getCharArray() {

? ? ? ? return charArray;

? ? }

? ? public String getTempString() {

? ? ? ? return tempString;

? ? }

}


創(chuàng)建測試類:

public class TestA {

? ? public static void main(String[] args) {

? ? ? ? A a1=new? A();

? ? ? ? A a2=new A();

? ? ? ? System.out.println(a1.charArray==a2.charArray);

? ? ? ? System.out.println(a1.tempString==a2.tempString);

? ? }

}


輸出結果:

false

true


要想明白上面字符串對比為什么輸出為true你必須知道:

該圖片截自《深入理解Java虛擬機》

一個Class字節(jié)碼文件的Class字節(jié)碼文件對象只有一個常量池柴灯,常量池被所有線程共享。

在常量池中费尽,字符串被存儲為一個字符序列赠群,每個字符序列都對應一個String對象,該對象保存在堆中旱幼。所以也就是說為什么String

temp=“xxx”;能夠當成一個對象使用2槊琛!

如果多個線程去訪問A類中的String字符串柏卤,每次都會到常量區(qū)中去找該字符序列的引用冬三。

所以訪問A類被創(chuàng)建的兩個A類型對象的String字符串對比會輸出true。

如果對字符串輸出為true還是不懂缘缚,可以參考這篇博客:字符串被存儲的原理過程

那么為什么final類型的字符數(shù)組就不為true了呢勾笆??

申明(不管是通過new還是通過直接寫一個數(shù)組)一個數(shù)組其實在Java中就等同創(chuàng)建了一個對象桥滨,即每次創(chuàng)建類的對象都會自動創(chuàng)建一個新的數(shù)組空間窝爪。

其中要注意的是:常量池中存儲字符數(shù)組只是存儲的是每個字符或者字符串。

為了證明每次獲取的final數(shù)組地址不一樣齐媒,并且數(shù)組中的字符都會存儲在常量池中蒲每,我們需要參考另外一個代碼:

public class A {

? ? public String tempString="world";

? ? public final String tempStringArray[]={"Fire","Lang"};

? ? public final char[] charArray={'h','e','l','l','o'};

? ? public Character charx='l';

? ? public char[] getCharArray() {

? ? ? ? return charArray;

? ? }

? ? public String getTempString() {

? ? ? ? return tempString;

? ? }

? ? public String[] getTempStringArray() {

? ? ? ? return tempStringArray;

? ? }

? ? public Character getCharx() {

? ? ? ? return charx;

? ? }

}


測試代碼:

public class TestA {

? ? public static void main(String[] args) {

? ? ? ? A a1=new? A();

? ? ? ? A a2=new A();

? ? ? ? System.out.println(a1.tempString==a2.tempString);

? ? ? ? System.out.println(a1.tempStringArray==a2.tempStringArray);//看這里

? ? ? ? System.out.println("#####################");//看這里

? ? ? ? System.out.println(a1.tempStringArray[0]==a2.tempStringArray[0]);

? ? ? ? System.out.println(a1.tempStringArray[0]=="Fire");

? ? ? ? System.out.println("#####################");

? ? ? ? System.out.println(a1.charArray==a2.charArray);

? ? ? ? System.out.println(a1.charx==a2.charx);

? ? }

}


輸出:

true

false

#####################

true

true

#####################

false

true


可以看到每次輸出的final數(shù)組地址都不一樣,最重要的是String類型的數(shù)組地址也都不一樣S骼ā邀杏!但是String類型數(shù)組中的每個字符串都存儲在常量池中。

所以可以肯定的是字符串和其它能夠確定值的final字面量值是存儲在常量池的K痢淮阐!并且在方法區(qū)內(nèi)存中只有一份!刁品!與所有線程共享訪問F亍!

常量池存儲的項目類型:

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末挑随,一起剝皮案震驚了整個濱河市状您,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌兜挨,老刑警劉巖膏孟,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拌汇,居然都是意外死亡柒桑,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門噪舀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來魁淳,“玉大人,你說我怎么就攤上這事与倡〗绻洌” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵纺座,是天一觀的道長息拜。 經(jīng)常有香客問我,道長净响,這世上最難降的妖魔是什么少欺? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮馋贤,結果婚禮上狈茉,老公的妹妹穿的比我還像新娘。我一直安慰自己掸掸,他們只是感情好氯庆,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著扰付,像睡著了一般堤撵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上羽莺,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天实昨,我揣著相機與錄音,去河邊找鬼盐固。 笑死荒给,一個胖子當著我的面吹牛丈挟,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播志电,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼曙咽,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了挑辆?” 一聲冷哼從身側(cè)響起例朱,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鱼蝉,沒想到半個月后洒嗤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡魁亦,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年渔隶,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洁奈。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡派撕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出睬魂,到底是詐尸還是另有隱情终吼,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布氯哮,位于F島的核電站际跪,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏喉钢。R本人自食惡果不足惜姆打,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望肠虽。 院中可真熱鬧幔戏,春花似錦、人聲如沸税课。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽韩玩。三九已至垒玲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間找颓,已是汗流浹背合愈。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人佛析。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓益老,卻偏偏與公主長得像,于是被迫代替她去往敵國和親寸莫。 傳聞我的和親對象是個殘疾皇子捺萌,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

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