<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          《深入理解 Java 虛擬機》把這個知識點講錯了?

          共 2130字,需瀏覽 5分鐘

           ·

          2021-12-18 20:16

          △Hollis, 一個對Coding有著獨特追求的人△
          這是Hollis的第?380?篇原創(chuàng)分享
          作者 l Hollis
          來源 l Hollis(ID:hollischuang)
          在之前的一篇文章中,介紹過Java中的Class常量池,在Java體系中,提到常量池,除了 Class常量池,還有運行時常量池和字符串常量池等概念。
          很多人搞不清楚他們的區(qū)別與聯(lián)系,甚至還有人曾經(jīng)有人對周志明老師的《深入理解 Java虛擬機》中關于這他們之間的關系的表述產(chǎn)生過質(zhì)疑,詳見后文。
          那么,到底什么是運行時常量池。他和字符串池之間的關系和區(qū)別又是什么呢?
          Java虛擬機為每一個類型都維護了一個常量池,是 Java 虛擬機中的運行時數(shù)據(jù)結構,這里面主要存放的是編譯期生成的各種字面量和符號引用,這就是運行時常量池。
          根據(jù)Java虛擬機規(guī)范約定:每一個運行時常量池都在Java虛擬機的方法區(qū)中分配,在加載類和接口到虛擬機后,就創(chuàng)建對應的運行時常量池。
          規(guī)范中規(guī)定了運行時常量池屬于方法區(qū),但是沒規(guī)定方法區(qū)屬于哪。于是虛擬機在各自實現(xiàn)的時候就各顯神通了。



          JDK各個版本中的實現(xiàn)
          在不同版本的JDK中,運行時常量池所處的位置也不一樣。以HotSpot虛擬機為例:
          在JDK 1.7之前,方法區(qū)位于永久代,運行時常量池作為方法區(qū)的一部分,也處于永久代中。
          因為使用永久代實現(xiàn)方法區(qū)可能導致內(nèi)存泄露問題,所以,從JDK1.7開始,JVM嘗試解決這一問題。
          在JDK 1.7中,靜態(tài)變量和運行時常量池中的字符串常量池轉移到了堆內(nèi)存中,其他類型的變量還保留在方法區(qū)中。
          在JDK 1.8中,徹底移除了永久代,方法區(qū)通過元空間的方式實現(xiàn)。隨之,運行時常量池也在元空間中實現(xiàn)。



          池中常量的來源
          運行時常量池中包含了若干種不同的常量,他的來源主要有兩種:
          編譯期可知的字面量和符號引用(來自Class常量池)
          運行期解析后可獲得的常量(如String的intern方法)



          三種池之間的關系
          虛擬機啟動過程中,會將各個Class文件中的常量池載入到運行時常量池中。
          所以, Class常量池只是一個媒介場所。在JVM真的運行時,需要把常量池中的常量加載到內(nèi)存中,進入到運行時常量池。這就是Class 常量池和運行時常量池之間的關系。
          那么,字符串池(string literal pool)和運行時常量池(runtime constant pool)之間的關系和區(qū)別是什么呢?
          關于這個問題,很多人都有疑問。很少有人能說清楚到底這兩者之間有啥具體的區(qū)別和聯(lián)系。
          之前,就有人對周志明老師的《深入理解 Java虛擬機》中關于這二者之間的關系的表述產(chǎn)生過質(zhì)疑,于是兩個人各自舉證,唇槍舌戰(zhàn)的辯論了很久(圍觀地址:https://github.com/fenixsoft/jvm_book/issues/112 )。


          其實,這個事兒說來也簡單,主要是要區(qū)分「Java虛擬機規(guī)范」和「Java虛擬機實現(xiàn)」
          首先,在官方的「Java虛擬機規(guī)范」中,明確的表示過,字符串字面量以及 intern 過的字符串內(nèi)容,都是要進到運行時常量池的。
          規(guī)范是這么說的,所以,不管咋說,字符串常量就是要存儲在運行時常量池的。
          但是,具體的虛擬機實現(xiàn)的時候,可能有些自己的想法,如 HotSpot就給字符串常量池專門搞了個池用來存儲字符串常量。
          而有人認為這兩個不是一回事的主要原因,其實,"罪魁禍首"也是HotSpot。
          「Java虛擬機規(guī)范」規(guī)定運行時常量池要放到方法區(qū),但是沒規(guī)定方法區(qū)要具體在哪實現(xiàn)。
          如前文說過,JDK 1.8中,徹底移除了永久代,方法區(qū)通過元空間的方式實現(xiàn)。運行時常量池隨著去到了元空間中。
          但是!字符串池還保留在堆內(nèi)存中。
          這就使得很多人認為,運行時常量池和字符串常量池好像沒啥關系,所在的位置都不一樣。
          但是其實,不管 HotSpot 具體如何實現(xiàn)的,其實還是遵守「Java虛擬機規(guī)范」的,雖然在 JDK 1.8中,運行時常量池和字符串池不在同一個物理區(qū)域,但是這也不能說明字符串池不屬于運行時常量池。
          或者說,字符串池就是運行時常量池的一個邏輯子區(qū)域。及字符串池是運行時常量池的分池!
          所以,總結一下,Class 常量池的內(nèi)容,會在編譯過后在運行期進入到運行時常量池,其中字符串的部分直接進到字符串池,其他常量進入到運行時常量池。至于在運行期,如果有對字符串進行過 intern 操作,那么也可能會在運行時動態(tài)向字符串池中添加新的字符串常量!
          PS:本文節(jié)選自我已經(jīng)寫完但是還未出版的新書,敬請期待。

          推薦閱讀:

          跑了4個實驗,實戰(zhàn)講解 MySQL的行鎖、間隙鎖...

          Java 進階之字節(jié)碼剖析

          【硬核】秒殺活動技術方案中的Redis

          5 分鐘復現(xiàn) log4J 漏洞,手把手實現(xiàn)

          為什么CTO不寫代碼,還這么牛逼?

          面試官:HashMap有幾種遍歷方法?推薦使用哪種?



          互聯(lián)網(wǎng)全棧架構,。

          瀏覽 52
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  女人扒开腿让男人桶爽 | 91久久成人视频 | 精品国产AⅤ一区二区三区东京热 | 91人妻视频 | 国产免费大香蕉 |