成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

面試官:說下你對(duì)方法區(qū)演變過程和內(nèi)部結(jié)構(gòu)的理解

開發(fā) 前端
雖然 Java 虛擬機(jī)規(guī)范把方法區(qū)描述為堆的一個(gè)邏輯部分,但是它卻有一個(gè)別名叫做 Non-Heap(非堆),目的應(yīng)該是與 Java 堆區(qū)分開來。所以,方法區(qū)可以看作是一塊獨(dú)立于 Java 堆的內(nèi)存空間。

[[425846]]

之前我們已經(jīng)了解過“運(yùn)行時(shí)數(shù)據(jù)區(qū)”的程序計(jì)數(shù)器、虛擬機(jī)棧、本地方法棧和堆空間,今天我們就來了解一下最后一個(gè)模塊——方法區(qū)。

簡(jiǎn)介

創(chuàng)建對(duì)象時(shí)內(nèi)存分配簡(jiǎn)圖

《Java虛擬機(jī)規(guī)范》中明確說明:“盡管所有的方法區(qū)在邏輯上屬于堆的一部分,但一些簡(jiǎn)單的實(shí)現(xiàn)可能不會(huì)選擇去進(jìn)行垃圾收集或者進(jìn)行壓縮。”

雖然 Java 虛擬機(jī)規(guī)范把方法區(qū)描述為堆的一個(gè)邏輯部分,但是它卻有一個(gè)別名叫做 Non-Heap(非堆),目的應(yīng)該是與 Java 堆區(qū)分開來。所以,方法區(qū)可以看作是一塊獨(dú)立于 Java 堆的內(nèi)存空間。

方法區(qū)與 Java 堆一樣,是各個(gè)線程共享的內(nèi)存區(qū)域。方法區(qū)在 JVM 啟動(dòng)時(shí)就會(huì)被創(chuàng)建,并且它的實(shí)際的物理內(nèi)存空間是可以不連續(xù)的,關(guān)閉 JVM 就會(huì)釋放這個(gè)區(qū)域的內(nèi)存。

永久代、元空間

《java虛擬機(jī)規(guī)范》對(duì)如何實(shí)現(xiàn)方法區(qū),不做統(tǒng)一要求。例如:BEA JRockit/IBM J9 中不存在永久代的概念。而對(duì)于 HotSpot 來說,在 jdk7 及以前,習(xí)慣上把方法區(qū)的實(shí)現(xiàn)稱為永久代,而從 jdk8 開始,使用元空間取代了永久代。

方法區(qū)是 Java 虛擬機(jī)規(guī)范中的概念,而永久代和元空間是 HotSpot 虛擬機(jī)對(duì)方法區(qū)的一種實(shí)現(xiàn)。通俗點(diǎn)講:如果把方法區(qū)比作接口的話,那永久代和元空間可以比作實(shí)現(xiàn)該接口的實(shí)現(xiàn)類。

直接內(nèi)存

永久代、元空間并不只是名字變了,內(nèi)部結(jié)構(gòu)也進(jìn)行了調(diào)整。永久代使用的是 JVM 的內(nèi)存,而元空間使用的是本地的直接內(nèi)存。

直接內(nèi)存并不是 JVM 運(yùn)行時(shí)數(shù)據(jù)區(qū)的一部分,因此不會(huì)受到 Java 堆的限制。但是它會(huì)受到本機(jī)總內(nèi)存大小以及處理器尋址空間的限制,所以如果這部分內(nèi)存也被頻繁的使用,依然會(huì)導(dǎo)致 OOM 錯(cuò)誤的出現(xiàn)。

方法區(qū)的大小

方法區(qū)的大小是可以進(jìn)行設(shè)置的,可以選擇固定大小也可以進(jìn)行擴(kuò)展。

jdk7 及以前

  1. -XX:PermSize=N //方法區(qū) (永久代) 初始分配空間,默認(rèn)值為 20.75M 
  2. -XX:MaxPermSize=N //方法區(qū) (永久代) 最大可分配空間。32位機(jī)器默認(rèn)是64M,64位機(jī)器默認(rèn)是82M 

jdk8及以后

默認(rèn)值依賴于平臺(tái),windows下:

  1. -XX:MetaspaceSize=N //方法區(qū) (元空間) 初始分配空間,如果未指定此標(biāo)志,則元空間將根據(jù)運(yùn)行時(shí)的應(yīng)用程序需求動(dòng)態(tài)地重新調(diào)整大小。 
  2. -XX:MaxMetaspaceSize=N //方法區(qū) (元空間) 最大可分配空間,默認(rèn)值為 -1,即沒有限制 

與永久代很大的不同就是,如果不指定大小的話,隨著更多類的創(chuàng)建,虛擬機(jī)會(huì)耗盡所有可用的系統(tǒng)內(nèi)存。

方法區(qū)的大小決定了系統(tǒng)可以保存多少個(gè)類,如果系統(tǒng)定義了太多的類,比如:加載大量的第三方 jar 包、Tomcat 部署的工程過多、大量動(dòng)態(tài)生成反射類等都會(huì)導(dǎo)致方法區(qū)溢出,拋出內(nèi)存溢出錯(cuò)誤。

  • 永久代:OutOfMemoryError:PermGen space
  • 元空間:OutOfMemoryError:Metaspace

至于如何解決 OOM 異常,將在以后的文章中講解!

jvisualvm

我們可以通過 JDK 自帶的 jvisualvm 工具來查看程序加載的類文件:

  1. public class MethodAreaDemo1 { 
  2.     public static void main(String[] args) { 
  3.         System.out.println("start..."); 
  4.         try { 
  5.             Thread.sleep(1000000); 
  6.         } catch (InterruptedException e) { 
  7.             e.printStackTrace(); 
  8.         } 
  9.         System.out.println("end..."); 
  10.     } 

運(yùn)行程序,可以看到一個(gè)簡(jiǎn)單的程序就需要加載這么多的類文件。

高水位線

對(duì)于一個(gè)64位的服務(wù)器端 JVM 來說,XX:MetaspaceSize=21 就是初始的高水位線,一旦觸及這個(gè)水位線,F(xiàn)ull GC 將會(huì)被觸發(fā)并卸載沒用的類(即這些類對(duì)應(yīng)的類加載器不再存活),然后這個(gè)高水位線將會(huì)重置。

新的高水位線的值取決于 GC 后釋放了多少元空間:

  • 如果釋放的空間不足,那么在不超過 MaxMetaspaceSize 時(shí),適當(dāng)提高該值;
  • 如果釋放空間過多,則適當(dāng)降低該值。

如果初始化的高水位線設(shè)置過低,高水位線調(diào)整情況會(huì)發(fā)生很多次。通過垃圾回收器的日志可以觀察到 Full GC 多次調(diào)用。為了避免頻繁地GC,建議將 -XX :MetaspaceSize 設(shè)置為一個(gè)相對(duì)較高的值。

內(nèi)部結(jié)構(gòu)

《深入理解Java虛擬機(jī)》書中對(duì)方法區(qū)存儲(chǔ)內(nèi)容描述如下:它用于存儲(chǔ)已被虛擬機(jī)加載的類型信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼緩存等。接下來我們就一起來看一下它的內(nèi)部結(jié)構(gòu)。

類型信息

對(duì)每個(gè)加載的類型( 類 class、接口 interface、枚舉 enum、注解 annotation),JVM 必須在方法區(qū)中存儲(chǔ)以下類型信息:

這個(gè)類型的完整有效名稱(全名=包名.類名)

這個(gè)類型直接父類的完整有效名(對(duì)于 interface 或是 java. lang.Object ,都沒有父類)

這個(gè)類型的修飾符( public , abstract, final 的某個(gè)子集)

這個(gè)類型直接接口的一個(gè)有序列表

域(Field)信息

  1. JVM必須在方法區(qū)中保存類型的所有域(field,也稱為屬性)的相關(guān)信息以及域的聲明順序;
  2. 域的相關(guān)信息包括:域名稱、 域類型、域修飾符(public, private,protected, static, final, volatile, transient 的某個(gè)子集)

方法(Method)信息

JVM 必須保存所有方法的以下信息,同域信息一樣包括聲明順序:

  • 方法名稱
  • 方法的返回類型(或void)
  • 方法參數(shù)的數(shù)量和類型(按順序)
  • 方法的修飾符(public, private, protected, static, final,synchronized, native , abstract 的一個(gè)子集)
  • 方法的字節(jié)碼(bytecodes)、操作數(shù)棧、局部變量表及大小( abstract 和 native 方法除外)
  • 異常表( abstract 和 native 方法除外)每個(gè)異常處理的開始位置、結(jié)束位置、代碼處理在程序計(jì)數(shù)器中的偏移地址、被捕獲的異常類的常量池索引

non-final 的類變量

  • 靜態(tài)變量和類關(guān)聯(lián)在一起,隨著類的加載而加載,他們成為類數(shù)據(jù)在邏輯上的一部分
  • 類變量被類的所有實(shí)例所共享,即使沒有類實(shí)例你也可以訪問它。

我們可以通過例子來查看:

  1. public class MethodAreaDemo2 { 
  2.     public static void main(String[] args) { 
  3.         Order order = null
  4.         order.hello(); 
  5.         System.out.println(order.count); 
  6.     } 
  7.  
  8. class Order { 
  9.     public static int count = 1; 
  10.     public static final int number = 2; 
  11.  
  12.     public static void hello() { 
  13.         System.out.println("hello!"); 
  14.     } 

運(yùn)行結(jié)果為:

  1. hello! 

可以打開 IDEA 的 Terminal 窗口,在 MethodAreaDemo2.class 所在的路徑下,輸入 javap -v -p MethodAreaDemo2.class 命令

通過圖片我們可以看出被聲明為 final 的類變量的處理方法是不一樣的,全局常量在編譯的時(shí)候就被分配了。

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

說到運(yùn)行時(shí)常量池,我們先來了解一下什么是常量池表。

常量池表

一個(gè)有效的字節(jié)碼文件中除了包含類的版本信息、字段、方法以及接口等描述信息外,還包含一項(xiàng)信息那就是常量池表(Constant Pool Table),里邊存儲(chǔ)著數(shù)量值、字符串值、類引用、字段引用和方法引用。

為什么字節(jié)碼文件需要常量池?

java 源文件中的類、接口,編譯后會(huì)產(chǎn)生一個(gè)字節(jié)碼文件。而字節(jié)碼文件需要數(shù)據(jù)支持,通常這種數(shù)據(jù)會(huì)很大,以至于不能直接存放到字節(jié)碼中。換一種方式,可以將指向這些數(shù)據(jù)的符號(hào)引用存到字節(jié)碼文件的常量池中,這樣字節(jié)碼只需使用常量池就可以在運(yùn)行時(shí)通過動(dòng)態(tài)鏈接找到相應(yīng)的數(shù)據(jù)并使用。

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

運(yùn)行時(shí)常量池( Runtime Constant Pool)是方法區(qū)的一部分,類加載器加載字節(jié)碼文件時(shí),將常量池表加載進(jìn)方法區(qū)的運(yùn)行時(shí)常量池。運(yùn)行時(shí)常量池中包含多種不同的常量,包括編譯期就已經(jīng)明確的數(shù)值字面量,也包括到運(yùn)行期解析后才能夠獲得的方法或者字段引用。此時(shí)不再是常量池中的符號(hào)地址了,這里換為真實(shí)地址。

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

演進(jìn)細(xì)節(jié)

針對(duì)的是 Hotspot 的虛擬機(jī):

  • jdk1.6 及之前:有永久代 ,靜態(tài)變量存放在永久代上;
  • jdk1.7:有永久代,但已經(jīng)逐步“去永久代”,字符串常量池、靜態(tài)變量移除,保存在堆中;
  • jdk1.8及之后:無永久代,類型信息、字段、方法、常量保存在本地內(nèi)存的元空間,但字符串常量池、靜態(tài)變量仍在堆中;

演變示例圖

為什么要將永久代替換為元空間呢?

永久代使用的是 JVM 的內(nèi)存,受 JVM 設(shè)置的內(nèi)存大小限制;元空間使用的是本地直接內(nèi)存,它的最大可分配空間是系統(tǒng)可用內(nèi)存的空間。因?yàn)樵臻g里存放的是類的元數(shù)據(jù),所以隨著內(nèi)存空間的增大,能加載的類就更多了,相應(yīng)的溢出的機(jī)率會(huì)大大減小。

在 JDK8,合并 HotSpot 和 JRockit 的代碼時(shí),JRockit 從來沒有一個(gè)叫永久代的東西,合并之后就沒有必要額外的設(shè)置這么一個(gè)永久代的地方了。

對(duì)永久代進(jìn)行調(diào)優(yōu)是很困難的。

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

因?yàn)橛谰么幕厥招屎艿停?full gc 的時(shí)候才會(huì)觸發(fā)。而 full GC 是老年代的空間不足、永久代不足時(shí)才會(huì)觸發(fā)。這就導(dǎo)致了StringTable 回收效率不高。而我們開發(fā)中會(huì)有大量的字符串被創(chuàng)建,回收效率低,導(dǎo)致永久代內(nèi)存不足。放到堆里,能及時(shí)回收內(nèi)存。

垃圾回收

相對(duì)而言,垃圾收集行為在這個(gè)區(qū)域是比較少出現(xiàn)的,但并非數(shù)據(jù)進(jìn)入方法區(qū)后就“永久存在”了。方法區(qū)的垃圾收集主要回收兩部分內(nèi)容:常量池中廢奔的常量和不再使用的類型。

方法區(qū)內(nèi)常量池中主要存放字面量和符號(hào)引用兩大類常量:

  • 字面量比較接近 Java 語言層次的常量概念,如文本字符串、被聲明為 final 的常量值等。
  • 符號(hào)引用則屬于編譯原理方面的概念,包括類和接口的全限定名、字段的名稱和描述符、方法的名稱和描述符。

HotSpot 虛擬機(jī)對(duì)常量池的回收策略是很明確的,只要常量池中的常量沒有被任何地方引用,就可以被回收。

類型判定

判定一個(gè)常量是否“廢棄”還是相對(duì)簡(jiǎn)單,而要判定一個(gè)類型是否屬于“不再被使用的類”的條件就比較苛刻了。需要同時(shí)滿足下面三個(gè)條件:

  • 該類所有的實(shí)例都已經(jīng)被回收,也就是 Java 堆中不存在該類及其任何派生子類的實(shí)例;
  • 加載該類的類加載器已經(jīng)被回收,這個(gè)條件除非是經(jīng)過精心設(shè)計(jì)的可替換類加載器的場(chǎng)景,如OSGi、JSP的重加載等,否則通常是很難達(dá)成的;
  • 該類對(duì)應(yīng)的 java.lang.Class 對(duì)象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法。

Java 虛擬機(jī)被允許對(duì)滿足上述三個(gè)條件的無用類進(jìn)行回收,這里說的僅僅是“被允許”,而并不是和對(duì)象一樣,沒有引用了就必然會(huì)回收。

本文轉(zhuǎn)載自微信公眾號(hào)「阿Q說代碼」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系阿Q說代碼公眾號(hào)。

 

責(zé)任編輯:武曉燕 來源: 阿Q說代碼
相關(guān)推薦

2025-01-13 09:24:32

2025-03-07 00:00:10

2020-05-12 23:20:50

Tomcat內(nèi)部結(jié)構(gòu)

2019-07-26 06:42:28

PG架構(gòu)數(shù)據(jù)庫

2021-08-09 07:47:40

Git面試版本

2021-11-25 10:18:42

RESTfulJava互聯(lián)網(wǎng)

2022-03-21 09:05:18

volatileCPUJava

2024-10-24 16:14:43

數(shù)據(jù)傳輸CPU零拷貝

2025-03-21 00:00:05

Reactor設(shè)計(jì)模式I/O 機(jī)制

2020-12-01 08:47:36

Java異常開發(fā)

2024-09-27 15:43:52

零拷貝DMAIO

2025-02-21 15:25:54

虛擬線程輕量級(jí)

2020-06-12 15:50:56

options前端服務(wù)器

2015-08-13 10:29:12

面試面試官

2021-03-05 07:27:59

技術(shù)架構(gòu)演變

2024-09-25 12:26:14

2021-11-11 16:37:05

模板模式方法

2024-07-25 18:20:03

2020-06-19 15:32:56

HashMap面試代碼

2024-08-27 12:36:33

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 欧美在线日韩 | 在线日韩欧美 | 日韩欧美在线播放 | 免费在线观看毛片 | 一区视频在线 | 一区二区亚洲 | 亚洲视频精品在线 | 久久精品视频在线免费观看 | a爱视频 | 成人片免费看 | 久久福利电影 | 欧美性区| 黑人巨大精品 | 国产 欧美 日韩 一区 | 日韩中文字幕免费在线 | 中文字幕av在线播放 | 91福利网| 看片地址 | 亚洲欧美一区二区三区国产精品 | 久久精品一 | 国产精品色哟哟网站 | 日韩精品成人 | av毛片 | 午夜成人免费视频 | 91av免费观看 | 欧美成人免费在线视频 | 一区二区三区视频在线观看 | 一区二区三区国产在线观看 | 欧美日韩一区二区三区不卡视频 | 日日操夜夜操天天操 | 久久国产香蕉 | 成人免费视频网站在线看 | 一区二区三区四区电影视频在线观看 | 一区二区三区成人 | 国产精品一区免费 | 国产精品不卡视频 | 免费在线观看av片 | 在线看无码的免费网站 | 欧美男人亚洲天堂 | 国产真实乱全部视频 | 成人做爰999|