11-方法區(qū)的演進(jìn)以及StringTable的調(diào)整

image

《Java虛擬機(jī)規(guī)范》中明確說(shuō)明:“盡管所有的方法區(qū)在邏輯上是屬于堆的一部分电湘,但一些簡(jiǎn)單的實(shí)現(xiàn)可能不會(huì)選擇去進(jìn)行垃圾收集或者進(jìn)行壓縮。”但對(duì)于 HotSpotJVM 而言,方法區(qū)還有一個(gè)別名叫做Non-Heap(非堆)亡哄,目的就是要和堆分開。

所以布疙,方法區(qū)看作是一塊獨(dú)立于Java堆的內(nèi)存空間蚊惯。

方法區(qū)主要存放的是『Class』,而堆中主要存放的是『實(shí)例化的對(duì)象』

  • 方法區(qū)(Method Area)與Java堆一樣灵临,是各個(gè)線程共享的內(nèi)存區(qū)域截型。

  • 方法區(qū)在JVM啟動(dòng)的時(shí)候被創(chuàng)建,并且它的實(shí)際的物理內(nèi)存空間中和Java堆區(qū)一樣都可以是不連續(xù)的儒溉。

  • 方法區(qū)的大小宦焦,跟堆空間一樣,可以選擇固定大小或者可擴(kuò)展顿涣。

  • 方法區(qū)的大小決定了系統(tǒng)可以保存多少個(gè)類波闹,如果系統(tǒng)定義了太多的類,導(dǎo)致方法區(qū)溢出园骆,虛擬機(jī)同樣會(huì)拋出內(nèi)存溢出錯(cuò)誤:java.lang.OutofMemoryError:PermGen space 或者java.lang.OutOfMemoryError:Metaspace

  • 加載大量的第三方的jar包

  • Tomcat部署的工程過(guò)多(30 -- 50個(gè))

  • 大量動(dòng)態(tài)的生成反射類

  • 關(guān)閉JVM就會(huì)釋放這個(gè)區(qū)域的內(nèi)存舔痪。

1.HotSpot中方法區(qū)的演進(jìn)

在jdk7及以前寓调,習(xí)慣上把方法區(qū)锌唾,稱為永久代。jdk8開始夺英,使用元空間取代了永久代晌涕。

JDK 1.8后,元空間存放在堆外內(nèi)存中痛悯。

本質(zhì)上余黎,方法區(qū)和永久代并不等價(jià)。僅是對(duì)hotspot而言的载萌【宀疲《Java虛擬機(jī)規(guī)范》對(duì)如何實(shí)現(xiàn)方法區(qū)巡扇,不做統(tǒng)一要求。例如:BEAJRockit / IBM J9 中不存在永久代的概念垮衷。

現(xiàn)在來(lái)看厅翔,當(dāng)年使用永久代,不是好的idea搀突。導(dǎo)致Java程序更容易o(hù)om(超過(guò)-XX:MaxPermsize上限)

image

而到了JDK8刀闷,終于完全廢棄了永久代的概念,改用與JRockit仰迁、J9一樣在本地內(nèi)存中實(shí)現(xiàn)的元空間(Metaspace)來(lái)代替:

image

元空間的本質(zhì)和永久代類似甸昏,都是對(duì)JVM規(guī)范中方法區(qū)的實(shí)現(xiàn)。不過(guò)元空間與永久代最大的區(qū)別在于:元空間不在虛擬機(jī)設(shè)置的內(nèi)存中徐许,而是使用本地內(nèi)存施蜜。

永久代、元空間二者并不只是名字變了雌隅,內(nèi)部結(jié)構(gòu)也調(diào)整了花墩。

根據(jù)《Java虛擬機(jī)規(guī)范》的規(guī)定,如果方法區(qū)無(wú)法滿足新的內(nèi)存分配需求時(shí)澄步,將拋出OOM異常冰蘑。

2.方法區(qū)內(nèi)部結(jié)構(gòu)

《深入理解Java虛擬機(jī)》書中對(duì)方法區(qū)(Method Area)存儲(chǔ)內(nèi)容描述如下:它用于存儲(chǔ)已被虛擬機(jī)加載的類型信息、常量村缸、靜態(tài)變量祠肥、即時(shí)編譯器編譯后的代碼緩存等。

image

這里我們重點(diǎn)關(guān)注掌握運(yùn)行時(shí)常量池

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

方法區(qū)梯皿,內(nèi)部包含了運(yùn)行時(shí)常量池

image

要弄清楚方法區(qū)的運(yùn)行時(shí)常量池仇箱,需要理解清楚classFile中的常量池

  • 常量池

    一個(gè)有效的字節(jié)碼文件中除了包含類的版本信息、字段东羹、方法以及接口等描述符信息外剂桥,還包含一項(xiàng)信息就是常量池表(Constant Pool Table),包括各種字面量和對(duì)類型属提、域和方法的符號(hào)引用

image

常量池权逗、可以看做是一張表,虛擬機(jī)指令根據(jù)這張常量表找到要執(zhí)行的類名冤议、方法名斟薇、參數(shù)類型、字面量 等類型恕酸。

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

    運(yùn)行時(shí)常量池(Runtime Constant Pool)是方法區(qū)的一部分堪滨。

常量池表(Constant Pool Table)是Class文件的一部分,用于存放編譯期生成的各種字面量與符號(hào)引用蕊温,這部分內(nèi)容將在類加載后存放到方法區(qū)的運(yùn)行時(shí)常量池中袱箱。

運(yùn)行時(shí)常量池遏乔,在加載類和接口到虛擬機(jī)后,就會(huì)創(chuàng)建對(duì)應(yīng)的運(yùn)行時(shí)常量池发笔。

JVM為每個(gè)已加載的類型(類或接口)都維護(hù)一個(gè)常量池按灶。池中的數(shù)據(jù)項(xiàng)像數(shù)組項(xiàng)一樣,是通過(guò)索引訪問的筐咧。

運(yùn)行時(shí)常量池中包含多種不同的常量鸯旁,包括編譯期就已經(jīng)明確的數(shù)值字面量,也包括到運(yùn)行期解析后才能夠獲得的方法或者字段引用量蕊。此時(shí)不再是常量池中的符號(hào)地址了铺罢,這里換為真實(shí)地址。

運(yùn)行時(shí)常量池残炮,相對(duì)于Class文件常量池的另一重要特征是:具備動(dòng)態(tài)性韭赘。

運(yùn)行時(shí)常量池類似于傳統(tǒng)編程語(yǔ)言中的符號(hào)表(symboltable),但是它所包含的數(shù)據(jù)卻比符號(hào)表要更加豐富一些势就。

當(dāng)創(chuàng)建類或接口的運(yùn)行時(shí)常量池時(shí)泉瞻,如果構(gòu)造運(yùn)行時(shí)常量池所需的內(nèi)存空間超過(guò)了方法區(qū)所能提供的最大值,則JVM會(huì)拋outofMemoryError異常苞冯。

4.方法區(qū)的演進(jìn)細(xì)節(jié)

首先明確:只有Hotspot才有永久代袖牙。BEA JRockit、IBM J9等來(lái)說(shuō)舅锄,是不存在永久代的概念的鞭达。原則上如何實(shí)現(xiàn)方法區(qū)屬于虛擬機(jī)實(shí)現(xiàn)細(xì)節(jié),不受《Java虛擬機(jī)規(guī)范》管束皇忿,并不要求統(tǒng)一畴蹭。

Hotspot中方法區(qū)的變化:

版本 內(nèi)容
JDK1.6及以前 有永久代,靜態(tài)變量存儲(chǔ)在永久代上
JDK1.7 有永久代鳍烁,但已經(jīng)逐步 “去永久代”叨襟,字符串常量池,靜態(tài)變量移除幔荒,保存在堆中
JDK1.8 無(wú)永久代糊闽,類型信息,字段铺峭,方法墓怀,常量保存在本地內(nèi)存的元空間汽纠,但字符串常量池卫键、靜態(tài)變量仍然在堆中。

JDK6的時(shí)候:

image

JDK7的時(shí)候:

image

JDK8的時(shí)候虱朵,元空間大小只受物理內(nèi)存影響:

image

5.StringTable

StringTable叫做字符串常量池莉炉,用于存放字符串常量钓账,這樣當(dāng)我們使用相同的字符串對(duì)象時(shí),就可以直接從StringTable中獲取而不用重新創(chuàng)建對(duì)象絮宁。

StringTable為什么要調(diào)整位置

jdk7中將StringTable放到了堆空間中梆暮。因?yàn)橛谰么幕厥招屎艿停趂ull gc的時(shí)候才會(huì)觸發(fā)绍昂。而full gc是老年代的空間不足啦粹、永久代不足時(shí)才會(huì)觸發(fā)。

這就導(dǎo)致stringTable回收效率不高窘游。而我們開發(fā)中會(huì)有大量的字符串被創(chuàng)建唠椭,回收效率低,導(dǎo)致永久代內(nèi)存不足忍饰。放到堆里贪嫂,能及時(shí)回收內(nèi)存。

關(guān)于StringTable的深入講解艾蓝、垃圾回收力崇、性能調(diào)優(yōu)以及字符串的特點(diǎn)會(huì)結(jié)合視頻進(jìn)行講解發(fā)放

String相關(guān)的面試題如下:(可以自行思考)

<pre data-tool="mdnice編輯器" style="margin: 10px 0px; padding: 0px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">`String s1 = "a";
String s2 = "b";
String s3 = "a" + "b";
String s4 = s1 + s2;
String s5 = "ab";
String s6 = s4.intern();

// 問
System.out.println(s3 == s4);
System.out.println(s3 == s5);
System.out.println(s3 == s6);

String x2 = new String("c") + new String("d");
String x1 = "cd";
x2.intern();

// 問,如果調(diào)換了【最后兩行代碼】的位置呢赢织,如果是jdk1.6呢
System.out.println(x1 == x2);` </pre>

6.JVM內(nèi)存相關(guān)的幾個(gè)核心參數(shù)

在JVM內(nèi)存分配中亮靴,有幾個(gè)參數(shù)是比較核心的,我們總結(jié)歸納在一起:

指令 描述
-Xms Java堆內(nèi)存的大小
-Xmx Java堆內(nèi)存的最大大小
-Xmn Java堆內(nèi)存中的新生代大小于置,扣除新生代剩下的就是老年代的內(nèi)存大小
-XX:PermSize 永久代大小
-XX:MaxPermSize 永久代最大大小
-Xss 每個(gè)線程的棧內(nèi)存大小

7.系統(tǒng)啟動(dòng)的參數(shù)設(shè)置

我們可以在啟動(dòng)某個(gè)類或項(xiàng)目的時(shí)候進(jìn)行VM Options參數(shù)設(shè)置:

比如

image

運(yùn)行之前測(cè)試過(guò)的代碼台猴,結(jié)果跟設(shè)置一致:

image

總結(jié)

最后我們通過(guò)一個(gè)詳細(xì)圖對(duì)整個(gè)JVM的內(nèi)存結(jié)構(gòu)做一個(gè)總結(jié):

image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市俱两,隨后出現(xiàn)的幾起案子饱狂,更是在濱河造成了極大的恐慌,老刑警劉巖宪彩,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件休讳,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡尿孔,警方通過(guò)查閱死者的電腦和手機(jī)俊柔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)活合,“玉大人雏婶,你說(shuō)我怎么就攤上這事“字福” “怎么了留晚?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)告嘲。 經(jīng)常有香客問我错维,道長(zhǎng)奖地,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任赋焕,我火速辦了婚禮参歹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘隆判。我一直安慰自己犬庇,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布侨嘀。 她就那樣靜靜地躺著械筛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪飒炎。 梳的紋絲不亂的頭發(fā)上埋哟,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音郎汪,去河邊找鬼赤赊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛煞赢,可吹牛的內(nèi)容都是我干的抛计。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼照筑,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吹截!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起凝危,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤波俄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后蛾默,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體懦铺,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年支鸡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冬念。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡牧挣,死狀恐怖急前,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瀑构,我是刑警寧澤裆针,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響据块,放射性物質(zhì)發(fā)生泄漏码邻。R本人自食惡果不足惜折剃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一另假、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧怕犁,春花似錦边篮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至阵子,卻和暖如春思杯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背挠进。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工色乾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人领突。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓暖璧,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親君旦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子澎办,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

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