摘要:那方法區(qū)里都存著什么呢先拋結(jié)論靜態(tài)變量常量類信息構(gòu)造方法接口定義運行時常量池存在方法區(qū)中。動態(tài)常量池運行時常量池是方法區(qū)的一部分,是一塊內(nèi)存區(qū)域。文件常量池將在類加載后進入方法區(qū)的運行時常量池中存放。
一、方法區(qū)與永久代
這兩個是非常容易混淆的概念,永久代的對象放在方法區(qū)中,就會想當然地認為,方法區(qū)就等同于持久代的內(nèi)存區(qū)域。事實上兩者是這樣的關(guān)系:
《Java虛擬機規(guī)范》只是規(guī)定了有方法區(qū)這么個概念和它的作用,并沒有規(guī)定如何去實現(xiàn)它。那么,在不同的 JVM 上方法區(qū)的實現(xiàn)肯定是不同的了。 同時大多數(shù)用的JVM都是Sun公司的HotSpot。在HotSpot上把GC分代收集擴展至方法區(qū),或者說使用永久代來實現(xiàn)方法區(qū)。換句話說:方法區(qū)是一種規(guī)范,永久代是Hotspot針對這一規(guī)范的一種實現(xiàn)。而永久代本身也在迭代中:
在Java 6中,方法區(qū)中包含的數(shù)據(jù),除了JIT編譯生成的代碼存放在native memory的CodeCache區(qū)域,其他都存放在永久代;
在Java 7中,Symbol的存儲從PermGen移動到了native memory,并且把靜態(tài)變量從instanceKlass末尾(位于PermGen內(nèi))移動到了java.lang.Class對象的末尾(位于普通Java heap內(nèi));
在Java 8中,永久代被徹底移除,取而代之的是另一塊與堆不相連的本地內(nèi)存——元空間(Metaspace),?XX:MaxPermSize 參數(shù)失去了意義,取而代之的是-XX:MaxMetaspaceSize。
對于Java8, HotSpots取消了永久代,那么是不是也就沒有方法區(qū)了呢?當然不是,方法區(qū)是一個規(guī)范,規(guī)范沒變,它就一直在。那么取代永久代的就是元空間。它與永久代有什么不同的?
存儲位置不同,永久代是堆的一部分,和新生代,老年代地址是連續(xù)的,而元空間屬于本地內(nèi)存;
存儲內(nèi)容不同,元空間存儲類的元信息,靜態(tài)變量和常量池等并入堆中。相當于永久代的數(shù)據(jù)被分到了堆和元空間中。
二、方法區(qū)里存著什么?既然永久代是方法區(qū)的一種實現(xiàn),那么在Hotspot下,方法區(qū)就等于永久代,也被稱為非堆。那方法區(qū)里都存著什么呢?先拋結(jié)論:
靜態(tài)變量 + 常量 + 類信息(構(gòu)造方法/接口定義) + 運行時常量池存在方法區(qū)中 。
類信息與類常量池方法區(qū)里的class文件信息包括:魔數(shù),版本號,常量池,類,父類和接口數(shù)組,字段,方法等信息,其實類里面又包括字段和方法的信息。
在Class文件結(jié)構(gòu)中,最頭的4個字節(jié)用于存儲魔數(shù)Magic Number,用于確定一個文件是否能被JVM接受,再接著4個字節(jié)用于存儲版本號,前2個字節(jié)存儲次版本號,后2個存儲主版本號,再接著是用于存放常量的常量池,由于常量的數(shù)量是不固定的,所以常量池的入口放置一個U2類型的數(shù)據(jù)(constant_pool_count)存儲常量池容量計數(shù)值,參見下圖。
因此class文件信息和class文件常量池的關(guān)系如下圖:
圖中還包含一個運行時常量池,這個稍后會介紹。
class文件常量池中存儲了哪些內(nèi)部呢?
我們寫的每一個Java類被編譯后,就會形成一份class文件;class文件中除了包含類的版本、字段、方法、接口等描述信息外,還有一項信息就是常量池(constant pool table),用于存放編譯器生成的各種字面量(Literal)和符號引用(Symbolic References);
每個class文件都有一個class常量池。
動態(tài)常量池運行時常量池是方法區(qū)的一部分,是一塊內(nèi)存區(qū)域。Class 文件常量池將在類加載后進入方法區(qū)的運行時常量池中存放。一個類加載到 JVM 中后對應(yīng)一個運行時常量池,運行時常量池相對于 Class 文件常量池來說具備動態(tài)性,Class 文件常量只是一個靜態(tài)存儲結(jié)構(gòu),里面的引用都是符號引用。而運行時常量池可以在運行期間將符號引用解析為直接引用。可以說運行時常量池就是用來索引和查找字段和方法名稱和描述符的。給定任意一個方法或字段的索引,通過這個索引最終可得到該方法或字段所屬的類型信息和名稱及描述符信息,這涉及到方法的調(diào)用和字段獲取。
靜態(tài)常量池和動態(tài)常量池的關(guān)系以及區(qū)別靜態(tài)常量池存儲的是當class文件被java虛擬機加載進來后存放在方法區(qū)的一些字面量和符號引用,字面量包括字符串,基本類型的常量,符號引用其實引用的就是常量池里面的字符串,但符號引用不是直接存儲字符串,而是存儲字符串在常量池里的索引。
動態(tài)常量池是當class文件被加載完成后,java虛擬機會將靜態(tài)常量池里的內(nèi)容轉(zhuǎn)移到動態(tài)常量池里,在靜態(tài)常量池的符號引用有一部分是會被轉(zhuǎn)變?yōu)橹苯右玫?,比如說類的靜態(tài)方法或私有方法,實例構(gòu)造方法,父類方法,這是因為這些方法不能被重寫其他版本,所以能在加載的時候就可以將符號引用轉(zhuǎn)變?yōu)橹苯右?,而其他的一些方法是在這個方法被第一次調(diào)用的時候才會將符號引用轉(zhuǎn)變?yōu)橹苯右玫摹?/p> 本節(jié)總結(jié)
方法區(qū)里存儲著class文件信息和動態(tài)常量池,class文件的信息包括類信息和靜態(tài)常量池??梢詫㈩惖男畔⑹菍lass文件內(nèi)容的一個框架,里面具體的內(nèi)容通過常量池來存儲。
動態(tài)常量池里的內(nèi)容除了是靜態(tài)常量池里的內(nèi)容外,還將靜態(tài)常量池里的符號引用轉(zhuǎn)變?yōu)橹苯右?,而且動態(tài)常量池里的內(nèi)容是能動態(tài)添加的。例如調(diào)用String的intern方法就能將string的值添加到String常量池中,這里String常量池是包含在動態(tài)常量池里的,但在jdk1.8后,將String常量池放到了堆中。
三、jvm中的常量池在Java的內(nèi)存分配中,總共3種常量池:
字符串常量池(String Constant Pool):字符串常量池在Java內(nèi)存區(qū)域的哪個位置?
在JDK6.0及之前版本,字符串常量池是放在Perm Gen區(qū)(也就是方法區(qū))中;
在JDK7.0版本,字符串常量池被移到了堆中了。至于為什么移到堆內(nèi),大概是由于方法區(qū)的內(nèi)存空間太小了。
字符串常量池是什么?在HotSpot VM里實現(xiàn)的string pool功能的是一個StringTable類,它是一個Hash表,默認值大小長度是1009;這個StringTable在每個HotSpot VM的實例只有一份,被所有的類共享。字符串常量由一個一個字符組成,放在了StringTable上。
在JDK6.0中,StringTable的長度是固定的,長度就是1009,因此如果放入String Pool中的String非常多,就會造成hash沖突,導(dǎo)致鏈表過長,當調(diào)用String#intern()時會需要到鏈表上一個一個找,從而導(dǎo)致性能大幅度下降;
在JDK7.0中,StringTable的長度可以通過參數(shù)指定:
-XX:StringTableSize=66666
字符串常量池里放的是什么?在JDK6.0及之前版本中,String Pool里放的都是字符串常量;
在JDK7.0中,由于String#intern()發(fā)生了改變,因此String Pool中也可以存放放于堆內(nèi)的字符串對象的引用。關(guān)于String在內(nèi)存中的存儲和String#intern()方法的說明,可以參考我的另外一篇博客:
需要說明的是:字符串常量池中的字符串只存在一份!
如:
String s1 = "hello,world!"; String s2 = "hello,world!";
即執(zhí)行完第一行代碼后,常量池中已存在 “hello,world!”,那么 s2不會在常量池中申請新的空間,而是直接把已存在的字符串內(nèi)存地址返回給s2.
class常量池(Class Constant Pool):我們寫的每一個Java類被編譯后,就會形成一份class文件;class文件中除了包含類的版本、字段、方法、接口等描述信息外,還有一項信息就是常量池(constant pool table),用于存放編譯器生成的各種字面量(Literal)和符號引用(Symbolic References);
每個class文件都有一個class常量池。
運行時常量池(Runtime Constant Pool):運行時常量池存在于內(nèi)存中,也就是class常量池被加載到內(nèi)存之后的版本,不同之處是:它的字面量可以動態(tài)的添加(String#intern()),符號引用可以被解析為直接引用
JVM在執(zhí)行某個類的時候,必須經(jīng)過加載、連接、初始化,而連接又包括驗證、準備、解析三個階段。而當類加載到內(nèi)存中后,jvm就會將class常量池中的內(nèi)容存放到運行時常量池中,由此可知,運行時常量池也是每個類都有一個。在解析階段,會把符號引用替換為直接引用,解析的過程會去查詢字符串常量池,也就是我們上面所說的StringTable,以保證運行時常量池所引用的字符串與字符串常量池中是一致的。
常量池的好處常量池是為了避免頻繁的創(chuàng)建和銷毀對象而影響系統(tǒng)性能,其實現(xiàn)了對象的共享。
例如字符串常量池,在編譯階段就把所有的字符串文字放到一個常量池中。
(1)節(jié)省內(nèi)存空間:常量池中所有相同的字符串常量被合并,只占用一個空間。
(2)節(jié)省運行時間:比較字符串時,==比equals()快。對于兩個引用變量,只用==判斷引用是否相等,也就可以判斷實際值是否相等。
參考文檔https://www.zhihu.com/questio...
http://blog.csdn.net/vegetabl...
https://www.cnblogs.com/holos...
https://blog.csdn.net/vegetab...
https://blog.csdn.net/u011635...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/74388.html
摘要:參考的文章最權(quán)威的初認識一個不錯的東西理解等插件解析技術(shù)大漠的系列文章,應(yīng)用型很強,推薦一個年齡差不多的開發(fā)者的解釋一篇稍微理論化解釋的文章一個開發(fā)模式簡單的優(yōu)劣比較大家也可以直接閱讀我的博客 前言 最近大漠前輩在群里發(fā)關(guān)于PostCSS的系列文章,但是耗子姐姐又說看了有點云里霧里的感覺,所以這篇文章將按一個思考的角度來理解一下 PostCSS 到底是一個什么東西。 showImg(h...
摘要:收到報警年月號,正當大家熱情的討論人類首次拍攝的關(guān)于黑洞的照片的時候,突然收到了來自阿里云的報警,說是我們的一臺服務(wù)器正在對外攻擊趕緊登陸云控制臺,看看到底是怎么回事。收到報警 2019年4月10號,正當大家熱情的討論人類首次拍攝的關(guān)于黑洞的照片的時候,突然收到了來自阿里云的報警,說是我們的一臺服務(wù)器正在對外攻擊!趕緊登陸云控制臺,看看到底是怎么回事。 十有八九是中招了。。。登陸到服務(wù)器上去...
摘要:這個關(guān)鍵字到底返回的是什么我們簡單看一下返回的是一個叫做中文名就是生成器的對象,而這個生成器是實現(xiàn)了接口至于接口,你們?nèi)ナ謨陨纤阉靼伞? 其實,我并不是因為迭代或者生成器或者研究PHP手冊才認識的yield,要不是協(xié)程,我到現(xiàn)在也不知道PHP中還有yield這么個鬼東西。人家這個東西是從PHP 5.5就開始引入了,官方名稱叫做生成器。你要說為什么5.5年代的東西,現(xiàn)在才拿出來。我還想問你...
摘要:什么是回調(diào)首先一定要搞清楚回調(diào)的英文名什么是回電話假如你現(xiàn)在去一個商店買橘子,結(jié)果沒有橘子了店員說,現(xiàn)在供貨不穩(wěn)定,不知道啥時候才能有橘子商店進貨橘子商店進貨橘子然后,你和店員說,這樣吧,留個電話號碼給你,橘子一到貨,你就回個電話給我你的電 1.什么是回調(diào)? 首先一定要搞清楚回調(diào)的英文名 —— callback什么是callback?回電話 假如你現(xiàn)在去一個商店買橘子,結(jié)果沒有橘子了 ...
摘要:作為技術(shù)書籍或者視頻,講解一門語言的時候都是從最底層開始講解,底層的基礎(chǔ)有哪些呢首先是整個,讓我們對這門語言先混個臉熟,知道程序的基本結(jié)構(gòu),順帶著還會說一下注釋是什么樣子。 2018年新年剛過,就迷茫了,Java學(xué)不下去了,不知道從哪里學(xué)了。 那么多細節(jié)的東西,我根本記不住,看完就忘。 剛開始學(xué)習(xí)的時候熱情萬丈,持續(xù)不了幾天就慢慢退去。 作為技術(shù)書籍或者視頻,講解一門語言的時候都是...
閱讀 2788·2021-09-24 09:47
閱讀 4406·2021-08-27 13:10
閱讀 3055·2019-08-30 15:44
閱讀 1319·2019-08-29 12:56
閱讀 2627·2019-08-28 18:07
閱讀 2652·2019-08-26 14:05
閱讀 2634·2019-08-26 13:41
閱讀 1294·2019-08-26 13:33