《深入理解 Java 虚拟机》把这个知识点讲错了?
△Hollis, 一個對Coding有著獨特追求的人△
這是Hollis的第?380?篇原創分享
作者 l Hollis
來源 l Hollis(ID:hollischuang)
在之前的一篇文章中,介紹過Java中的Class常量池,在Java體系中,提到常量池,除了 Class常量池,還有運行時常量池和字符串常量池等概念。
很多人搞不清楚他們的區別與聯系,甚至還有人曾經有人對周志明老師的《深入理解 Java虛擬機》中關于這他們之間的關系的表述產生過質疑,詳見后文。
那么,到底什么是運行時常量池。他和字符串池之間的關系和區別又是什么呢?
Java虛擬機為每一個類型都維護了一個常量池,是 Java 虛擬機中的運行時數據結構,這里面主要存放的是編譯期生成的各種字面量和符號引用,這就是運行時常量池。
根據Java虛擬機規范約定:每一個運行時常量池都在Java虛擬機的方法區中分配,在加載類和接口到虛擬機后,就創建對應的運行時常量池。
規范中規定了運行時常量池屬于方法區,但是沒規定方法區屬于哪。于是虛擬機在各自實現的時候就各顯神通了。
JDK各個版本中的實現
在不同版本的JDK中,運行時常量池所處的位置也不一樣。以HotSpot虛擬機為例:
在JDK 1.7之前,方法區位于永久代,運行時常量池作為方法區的一部分,也處于永久代中。
因為使用永久代實現方法區可能導致內存泄露問題,所以,從JDK1.7開始,JVM嘗試解決這一問題。
在JDK 1.7中,靜態變量和運行時常量池中的字符串常量池轉移到了堆內存中,其他類型的變量還保留在方法區中。
在JDK 1.8中,徹底移除了永久代,方法區通過元空間的方式實現。隨之,運行時常量池也在元空間中實現。
池中常量的來源
運行時常量池中包含了若干種不同的常量,他的來源主要有兩種:
編譯期可知的字面量和符號引用(來自Class常量池)
運行期解析后可獲得的常量(如String的intern方法)
三種池之間的關系
虛擬機啟動過程中,會將各個Class文件中的常量池載入到運行時常量池中。
所以, Class常量池只是一個媒介場所。在JVM真的運行時,需要把常量池中的常量加載到內存中,進入到運行時常量池。這就是Class 常量池和運行時常量池之間的關系。
那么,字符串池(string literal pool)和運行時常量池(runtime constant pool)之間的關系和區別是什么呢?
關于這個問題,很多人都有疑問。很少有人能說清楚到底這兩者之間有啥具體的區別和聯系。
之前,就有人對周志明老師的《深入理解 Java虛擬機》中關于這二者之間的關系的表述產生過質疑,于是兩個人各自舉證,唇槍舌戰的辯論了很久(圍觀地址:https://github.com/fenixsoft/jvm_book/issues/112 )。
其實,這個事兒說來也簡單,主要是要區分「Java虛擬機規范」和「Java虛擬機實現」
首先,在官方的「Java虛擬機規范」中,明確的表示過,字符串字面量以及 intern 過的字符串內容,都是要進到運行時常量池的。
規范是這么說的,所以,不管咋說,字符串常量就是要存儲在運行時常量池的。
但是,具體的虛擬機實現的時候,可能有些自己的想法,如 HotSpot就給字符串常量池專門搞了個池用來存儲字符串常量。
而有人認為這兩個不是一回事的主要原因,其實,"罪魁禍首"也是HotSpot。
「Java虛擬機規范」規定運行時常量池要放到方法區,但是沒規定方法區要具體在哪實現。
如前文說過,JDK 1.8中,徹底移除了永久代,方法區通過元空間的方式實現。運行時常量池隨著去到了元空間中。
但是!字符串池還保留在堆內存中。
這就使得很多人認為,運行時常量池和字符串常量池好像沒啥關系,所在的位置都不一樣。
但是其實,不管 HotSpot 具體如何實現的,其實還是遵守「Java虛擬機規范」的,雖然在 JDK 1.8中,運行時常量池和字符串池不在同一個物理區域,但是這也不能說明字符串池不屬于運行時常量池。
或者說,字符串池就是運行時常量池的一個邏輯子區域。及字符串池是運行時常量池的分池!
所以,總結一下,Class 常量池的內容,會在編譯過后在運行期進入到運行時常量池,其中字符串的部分直接進到字符串池,其他常量進入到運行時常量池。至于在運行期,如果有對字符串進行過 intern 操作,那么也可能會在運行時動態向字符串池中添加新的字符串常量!
PS:本文節選自我已經寫完但是還未出版的新書,敬請期待。
技術交流群
最近有很多人問,有沒有讀者交流群,想知道怎么加入。
最近我創建了一些群,大家可以加入。交流群都是免費的,只需要大家加入之后不要隨便發廣告,多多交流技術就好了。
目前創建了多個交流群,全國交流群、北上廣杭深等各地區交流群、面試交流群、資源共享群等。
有興趣入群的同學,可長按掃描下方二維碼,一定要備注:全國 Or 城市 Or 面試 Or 資源,根據格式備注,可更快被通過且邀請進群。
▲長按掃描
往期推薦突發!Log4j 爆“核彈級”漏洞,Flink、Kafka等至少十多個項目受影響
一個員工的離職成本有多恐怖!
快手裁員30%,大部分年薪超100w?工資越高越容易被裁,你慌了嗎?
如果你喜歡本文,
請長按二維碼,關注?Hollis.
轉發至朋友圈,是對我最大的支持。
點個?在看?
喜歡是一種感覺
在看是一種支持
↘↘↘
總結
以上是生活随笔為你收集整理的《深入理解 Java 虚拟机》把这个知识点讲错了?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: thinkphp mysql save_
- 下一篇: mysql增错误_使用MySQL练习增删