講一講JVM的組成(Java經(jīng)典面試題)

JVM(Java 虛擬機)算是面試必問的問題的了,而但凡問 JVM 一定會問的第一個問題就是:講一講 JVM 的組成?那本文就注重講一下 JVM 的組成。
首先來說 JVM 的組成分為,整體組成部分和運行時數(shù)據(jù)區(qū)組成部分,一般開發(fā)者關(guān)注的和面試官問的都是后者,但本文會詳細講解以上兩個組成部分。
我們先把JVM這個虛擬機畫出來,如下圖所示:
virtual虛擬機
Machine 機械
java Virtual Machine (java 虛擬機)
從這個圖中可以看到,JVM是運行在操作系統(tǒng)之上的,它與硬件沒有直接的交互。我們再來看下JVM有哪些組成部分,如下圖所示:
一、JVM 整體組成
JVM 整體組成可分為以下四個部分:
- 類加載器(ClassLoader)
- 運行時數(shù)據(jù)區(qū)(Runtime Data Area)
- 執(zhí)行引擎(Execution Engine)
- 本地庫接口(Native Interface)
各個組成部分的用途:
程序在執(zhí)行之前先要把java代碼轉(zhuǎn)換成字節(jié)碼(class文件),jvm首先需要把字節(jié)碼通過一定的方式 類加載器(ClassLoader) 把文件加載到內(nèi)存中 運行時數(shù)據(jù)區(qū)(Runtime Data Area) ,而字節(jié)碼文件是jvm的一套指令集規(guī)范,并不能直接交個底層操作系統(tǒng)去執(zhí)行,因此需要特定的命令解析器 執(zhí)行引擎(Execution Engine) 將字節(jié)碼翻譯成底層系統(tǒng)指令再交由CPU去執(zhí)行,而這個過程中需要調(diào)用其他語言的接口 本地庫接口(Native Interface) 來實現(xiàn)整個程序的功能,這就是這4個主要組成部分的職責與功能。
而我們通常所說的jvm組成指的是運行時數(shù)據(jù)區(qū)(Runtime Data Area),因為通常需要程序員調(diào)試分析的區(qū)域就是“運行時數(shù)據(jù)區(qū)”,或者更具體的來說就是“運行時數(shù)據(jù)區(qū)”里面的Heap(堆)模塊,那接下來我們來看運行時數(shù)據(jù)區(qū)(Runtime Data Area)是由哪些模塊組成的。
二、運行時數(shù)據(jù)區(qū)組成
jvm的運行時數(shù)據(jù)區(qū),不同虛擬機實現(xiàn)可能略微有所不同,但都會遵從Java虛擬機規(guī)范,Java 8 虛擬機規(guī)范規(guī)定,Java虛擬機所管理的內(nèi)存將會包括以下幾個運行時數(shù)據(jù)區(qū)域:
程序計數(shù)器(Program Counter Register)
Java虛擬機棧(Java Virtual Machine Stacks)
本地方法棧(Native Method Stack)
Java堆(Java Heap)
方法區(qū)(Methed Area)
接下來我們分別介紹每個區(qū)域的用途。
①、Java程序計數(shù)器
程序計數(shù)器(Program Counter Register)是一塊較小的內(nèi)存空間,它可以看作是當前線程所執(zhí)行的字節(jié)碼的行號指示器。在虛擬機的概念模型里,字節(jié)碼解析器的工作是通過改變這個計數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令,分支、循環(huán)、跳轉(zhuǎn)、異常處理、線程恢復(fù)等基礎(chǔ)功能都需要依賴這個計數(shù)器來完成。
特性:內(nèi)存私有
由于jvm的多線程是通過線程輪流切換并分配處理器執(zhí)行時間的方式來實現(xiàn)的,也就是任何時刻,一個處理器(或者說一個內(nèi)核)都只會執(zhí)行一條線程中的指令。因此為了線程切換后能恢復(fù)到正確的執(zhí)行位置,每個線程都有獨立的程序計數(shù)器。
異常規(guī)定:無
如果線程正在執(zhí)行Java中的方法,程序計數(shù)器記錄的就是正在執(zhí)行虛擬機字節(jié)碼指令的地址,如果是Native方法,這個計數(shù)器就為空(undefined),因此該內(nèi)存區(qū)域是唯一一個在Java虛擬機規(guī)范中沒有規(guī)定OutOfMemoryError的區(qū)域。
②、Java虛擬機棧
Java虛擬機棧(Java Virtual Machine Stacks)描述的是Java方法執(zhí)行的內(nèi)存模型,每個方法在執(zhí)行的同時都會創(chuàng)建一個線幀(Stack Frame)用于存儲局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口等信息,每個方法從調(diào)用直至執(zhí)行完成的過程,都對應(yīng)著一個線幀在虛擬機棧中入棧到出棧的過程。
特性:內(nèi)存私有,它的生命周期和線程相同。
異常規(guī)定:StackOverflowError、OutOfMemoryError
1、如果線程請求的棧深度大于虛擬機所允許的棧深度就會拋出StackOverflowError異常。
2、如果虛擬機是可以動態(tài)擴展的,如果擴展時無法申請到足夠的內(nèi)存就會拋出OutOfMemoryError異常。
③、本地方法棧
本地方法棧(Native Method Stack)與虛擬機棧的作用是一樣的,只不過虛擬機棧是服務(wù)Java方法的,而本地方法棧是為虛擬機調(diào)用Native方法服務(wù)的。
在Java虛擬機規(guī)范中對于本地方法棧沒有特殊的要求,虛擬機可以自由的實現(xiàn)它,因此在Sun HotSpot虛擬機直接把本地方法棧和虛擬機棧合二為一了。
特性和異常:同虛擬機棧,請參考上面知識點。
④、Java堆
Java堆(Java Heap)是Java虛擬機中內(nèi)存最大的一塊,是被所有線程共享的,在虛擬機啟動時候創(chuàng)建,Java堆唯一的目的就是存放對象實例,幾乎所有的對象實例都在這里分配內(nèi)存,隨著JIT編譯器的發(fā)展和逃逸分析技術(shù)的逐漸成熟,棧上分配、標量替換優(yōu)化的技術(shù)將會導(dǎo)致一些微妙的變化,所有的對象都分配在堆上漸漸變得不那么“絕對”了。
特性:內(nèi)存共享
異常規(guī)定:OutOfMemoryError
如果在堆中沒有內(nèi)存完成實例分配,并且堆不可以再擴展時,將會拋出OutOfMemoryError。
Java虛擬機規(guī)范規(guī)定,Java堆可以處在物理上不連續(xù)的內(nèi)存空間中,只要邏輯上連續(xù)即可,就像我們的磁盤空間一樣。在實現(xiàn)上也可以是固定大小的,也可以是可擴展的,不過當前主流的虛擬機都是可擴展的,通過-Xmx和-Xms控制。
⑤、方法區(qū)
方法區(qū)(Methed Area)用于存儲已被虛擬機加載的類信息、常量、靜態(tài)變量、即時編譯后的代碼等數(shù)據(jù)。
誤區(qū):方法區(qū)不等于永生代
很多人原因把方法區(qū)稱作“永久代”(Permanent Generation),本質(zhì)上兩者并不等價,只是HotSpot虛擬機垃圾回收器團隊把GC分代收集擴展到了方法區(qū),或者說是用來永久代來實現(xiàn)方法區(qū)而已,這樣能省去專門為方法區(qū)編寫內(nèi)存管理的代碼,但是在Jdk8也移除了“永久代”,使用Native Memory來實現(xiàn)方法區(qū)。
特性:內(nèi)存共享
異常規(guī)定:OutOfMemoryError
當方法無法滿足內(nèi)存分配需求時會拋出OutOfMemoryError異常。
三、擴展知識
本節(jié)將擴展一些和內(nèi)存分配有關(guān)的知識。
運行時常量池
運行時常量池是方法區(qū)的一部分,Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池(Constant Pool Table)用于存放編譯期生成的各種字面量和符號引用,這部分在類加載后進入方法區(qū)的運行是常量池中,如String類的intern()方法。
直接內(nèi)存
直接內(nèi)存(Direct Memory)并不是虛擬機運行時數(shù)據(jù)區(qū)的一部分,但這部分內(nèi)存也會被頻繁的使用,而且可能導(dǎo)致OutOfMemoryError。在JDK 1.4中新加入了NIO類,引入了一種基于Channel與緩沖區(qū)Buffer的IO方式,它通過一個存儲在Java堆中的DirectByteBuffer對象作為這塊內(nèi)存的引用操作,它因此更高效,它避免了Java堆和Native堆來回交換數(shù)據(jù)的時間。
注意:直接內(nèi)存分配不會受到Java堆大小的限制,但是受到本機總內(nèi)存大小限制,在設(shè)置虛擬機參數(shù)的時候,不能忽略直接內(nèi)存,把實際內(nèi)存設(shè)置為-Xmx,使得內(nèi)存區(qū)域的總和大于物理內(nèi)存的限制,從而導(dǎo)致動態(tài)擴展時出現(xiàn)OutOfMemoryError異常。
四、總結(jié)
本文講了jvm的主要組成部分,以及組成部分中最重要的運行時數(shù)據(jù)區(qū)(Runtime Data Area)的構(gòu)成,其中程序計數(shù)器、虛擬機棧和本地方法為私有內(nèi)存,會隨著線程而生,隨著線程而滅,而Java堆作為最大的內(nèi)存區(qū)域?qū)⑹情_發(fā)人員重點關(guān)注的內(nèi)存區(qū)域,還有方法區(qū)以及運行時常量區(qū)與永生代的關(guān)系,最后講了直接內(nèi)存的實現(xiàn)過程已經(jīng)使用時需要主要的點,希望能夠幫助大家更好的理解jvm。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
- 這篇文章主要介紹了10道JVM常見面試題解析(附答案),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學2020-09-04
- 這篇文章主要介紹了JVM相關(guān)面試題及答案(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2020-09-02
2020面試阿里字節(jié)跳動90%被問到的JVM面試題附答案(史上最全)
這篇文章主要介紹了2020面試阿里字節(jié)跳動90%被問到的JVM面試題附答案,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2020-06-15- 這篇文章主要介紹了2020年JVM高頻率面試題整理,真是小編下了血本給大家整理出來的,值得大家收藏,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-03-09
- 這篇文章主要介紹了JVM面試題小結(jié)(2020最新版),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2020-02-21
- 這篇文章主要介紹了2019年JVM面試都問了什么?(附答案解析),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-12-04
Java研發(fā)面試99題(含答案):JVM+Spring+MySQL+線程池+鎖
這篇文章主要介紹了Java研發(fā)面試99題,主要包括了JVM,Spring,MySQL,線程池,鎖等,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-07-16- 這篇文章主要介紹了30道有趣的JVM面試題(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2020-11-26