第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

JVM 方法區(qū)

1. 前言

本節(jié)主要講解運行時數(shù)據(jù)區(qū)的方法區(qū)。本節(jié)主要知識點如下:

  • 了解方法區(qū)的作用及意義,為本節(jié)的基礎(chǔ)知識;
  • 了解方法區(qū)存放數(shù)據(jù)類型,為本節(jié)重點內(nèi)容之一;
  • 了解運行時常量池,我們在學習Class文件結(jié)構(gòu)的時候,也學習過常量池結(jié)構(gòu),那么運行時常量池本節(jié)課程會進行講解;
  • 了解方法區(qū)與堆內(nèi)存結(jié)構(gòu)的關(guān)系,以JDK 1.8 版本為分界線,進行對比講解,為本節(jié)重點內(nèi)容之一。

2. 什么是方法區(qū)

定義:方法區(qū),也稱非堆(Non-Heap),是一個被線程共享的內(nèi)存區(qū)域。其中主要存儲加載的類字節(jié)碼、class/method/field 等元數(shù)據(jù)對象、static-final 常量、static 變量、JIT 編譯器編譯后的代碼等數(shù)據(jù)。另外,方法區(qū)包含了一個特殊的區(qū)域 “運行時常量池”。

Tips:對于運行時常量池,后文會有講解。

對于習慣在 HotSpot 虛擬機上開發(fā)和部署程序的開發(fā)者來說,很多人愿意把方法區(qū)稱為 “永久代”(Permanent Generation),本質(zhì)上兩者并不等價,僅僅是因為 HotSpot 虛擬機的設(shè)計團隊選擇把 GC 分代收集擴展至方法區(qū),或者說使用永久代來實現(xiàn)方法區(qū)而已。對于其他虛擬機(如 BEA JRockit、IBM J9 等)來說是不存在永久代的概念的。

3. 方法區(qū)存放的數(shù)據(jù)

在講解方法區(qū)內(nèi)存放的數(shù)據(jù)之前,我們先通過示意圖來直觀的看下,方法區(qū)存放的數(shù)據(jù)與堆內(nèi)存之間的關(guān)系。如下圖所示:

圖片描述

從圖中可以看到,方法區(qū)存放了 ClassLoader 對象的引用,也存放了一個到類對象的引用,這兩個引用的對象實例會存放到堆內(nèi)存中。從上圖我們就可以簡單的了解到方法區(qū)存放的數(shù)據(jù)是什么,接下來,我們對存放的數(shù)據(jù)類型進行解釋。

  • 類型全限定名:全限定名為 package 路徑與類名稱組合起來的路徑;
  • 類型的直接超類的全限定名:父類或超類的全限定名;
  • 類型是類類型還是接口類型:判定當前類是 Class 還是接口 Interface;
  • 類型的訪問修飾符:判斷修飾符,如 pulic,private 等;
  • 類型的常量池:這部分會在下文進行講解;
  • 字段信息:類中字段的信息;
  • 方法信息:類中方法的信息;
  • 靜態(tài)變量:類中的靜態(tài)變量信息;
  • 一個到類 ClassLoader 的引用:對 ClassLoader 的引用,這個引用指向?qū)?nèi)存;
  • 一個到 Class 類的引用:對對象實例的引用,這個引用指向?qū)?nèi)存。

4. 運行時常量池

我們先來回顧下Class 文件結(jié)構(gòu)中的常量池的相關(guān)知識。

Class 文件中的常量池
在 Class 文件結(jié)構(gòu)中,最頭的 4 個字節(jié)用于存儲 Megic Number,用于確定一個文件是否能被 JVM 接受,再接著 4 個字節(jié)用于存儲版本號,前 2 個字節(jié)存儲次版本號,后 2 個存儲主版本號,再接著是用于存放常量的常量池,由于常量的數(shù)量是不固定的,所以常量池的入口放置一個 u2 類型的數(shù)據(jù) (constant_pool_count) 存儲常量池容量計數(shù)值。

常量池主要用于存放兩大類常量:字面量(Literal)和符號引用量(Symbolic References)。更加具體的知識,同學們可以翻看之前相關(guān)的小節(jié)內(nèi)容。

運行時常量池:我們回到正題,來看下運行時常量池。

Tips:其實 Class 文件中的常量池與運行時常量池的關(guān)系非常容易理解,Class 文件中的常量池用于存放編譯期生成的各種字面量和符號引用,這部分內(nèi)容將在類加載后進入方法區(qū)的運行時常量池中存放。簡單總結(jié)來說,編譯器使用 Class 文件中的常量池,運行期使用運行時常量池。

運行時常量池相對于 Class 文件常量池的另外一個重要特征是具備動態(tài)性,Java 語言并不要求常量一定只有編譯期才能產(chǎn)生,也就是并非預(yù)置入 Class 文件中常量池的內(nèi)容才能進入方法區(qū)運行時常量池,運行期間也可能將新的常量放入池中,這種特性被開發(fā)人員利用比較多的就是 String 類的 intern() 方法。

5. 常量池的優(yōu)勢

常量池是為了避免頻繁的創(chuàng)建和銷毀對象而影響系統(tǒng)性能,其實現(xiàn)了對象的共享。

例如字符串常量池,在編譯階段就把所有的字符串文字放到一個常量池中。

  • 節(jié)省內(nèi)存空間:常量池中所有相同的字符串常量被合并,只占用一個空間。
  • 節(jié)省運行時間:比較字符串時,==equals () 快。對于兩個引用變量,只用 == 判斷引用是否相等,也就可以判斷實際值是否相等。

6. 方法區(qū)內(nèi)存變更

圖片描述

方法區(qū)的實現(xiàn),虛擬機規(guī)范中并未明確規(guī)定,目前有 2 種比較主流的實現(xiàn)方式:

HotSpot 虛擬機 1.8之前:在 JDK1.6 及之前版本,HotSpot 使用 “永久代(permanent generation)” 的概念作為實現(xiàn),即將 GC 分代收集擴展至方法區(qū)。這種實現(xiàn)比較偷懶,可以不必為方法區(qū)編寫專門的內(nèi)存管理,但帶來的后果是容易碰到內(nèi)存溢出的問題(因為永久代有 - XX:MaxPermSize 的上限)。

在 JDK1.7,HotSpot 逐漸改變方法區(qū)的實現(xiàn)方式,如 1.7 版本移除了方法區(qū)中的字符串常量池,但為發(fā)生本質(zhì)的變化。

HotSpot 虛擬機 1.8之后:1.8 版本中移除了方法區(qū)并使用 metaspace(元數(shù)據(jù)空間)作為替代實現(xiàn)。metaspace 占用系統(tǒng)內(nèi)存,也就是說,只要不碰觸到系統(tǒng)內(nèi)存上限,方法區(qū)會有足夠的內(nèi)存空間。但這不意味著我們不對方法區(qū)進行限制,如果方法區(qū)無限膨脹,最終會導(dǎo)致系統(tǒng)崩潰。

7. 小結(jié)

本節(jié)主要講解了運行時數(shù)據(jù)區(qū)里邊的方法區(qū),方法區(qū)是一塊共享內(nèi)存區(qū)域,在運行時數(shù)據(jù)區(qū)占據(jù)著十分重要的位置。我們了解了方法區(qū)里邊存儲的數(shù)據(jù)類型,也了解到了方法區(qū)的作用,同時了解了方法區(qū)內(nèi)存的版本變更,通篇皆為重點知識,學習者需要用心學習。