Java虚拟机简单介绍
安裝jdk之后一般都會(huì)安裝jre,在jre中就包含有Java虛擬機(jī)(jvm).
jvm是虛擬出來的,類似于簡(jiǎn)單的系統(tǒng),有自己的內(nèi)存管理,寄存器,程序計(jì)數(shù)器cp,環(huán)境指針和棧指針等。
1.先說Java虛擬機(jī)的內(nèi)存管理
?(1)寄存器
? ?JVM只設(shè)置了4個(gè)最為常用的寄存器。它們是:
? ?pc程序計(jì)數(shù)器,用于記錄程序的執(zhí)行。
? ?optop操作數(shù)棧頂指針 ,記錄指向Java棧區(qū)的指針。
? ?frame當(dāng)前執(zhí)行環(huán)境指針, 記錄指向Java棧區(qū)的指針。
? ?vars指向當(dāng)前執(zhí)行環(huán)境中第一個(gè)局部變量的指針,記錄指向Java棧區(qū)的指針。
? ?所有寄存器均為32位。
?(2)jvm的棧結(jié)構(gòu)
? 這個(gè)極為重要,對(duì)理解代碼底層。
? Java棧是JVM存儲(chǔ)信息的主要方法。Java代碼中一個(gè)任何類的每一個(gè)方法調(diào)用都會(huì)創(chuàng)建一個(gè)棧框架,以保存該方法的狀態(tài)信息。注意:這里面的棧框架是指不是一個(gè)棧結(jié)構(gòu), ? 而 是很多的棧結(jié)構(gòu)。一般只要有{},就代表這一個(gè)棧結(jié)構(gòu)。“{” 進(jìn)棧,“}”出棧。
? 是由一個(gè)一個(gè)的棧幀組成的后進(jìn)先出的棧式結(jié)構(gòu),棧楨中存放方法運(yùn)行時(shí)產(chǎn)生的局部變量、方法出口等信息。
? 當(dāng)調(diào)用一個(gè)方法時(shí),虛擬機(jī)棧中就會(huì)創(chuàng)建一個(gè)棧幀存放這些數(shù)據(jù),當(dāng)方法調(diào)用完成時(shí),棧幀消失,如果方法中調(diào)用了其他方法,
? 則繼續(xù)在棧頂創(chuàng)建新的棧楨。
? 棧框架包括以下三類信息:
? 局部變量
? 局部變量用于存儲(chǔ)一個(gè)類的方法中所用到的局部變量。vars寄存器指向該變量表中的第一個(gè)局部變量。
? 每個(gè)Java方法使用一個(gè)固定大小的局部變量集。
? 執(zhí)行環(huán)境
? 執(zhí)行環(huán)境用于保存解釋器對(duì)Java字節(jié)碼進(jìn)行解釋過程中所需的信息:上次調(diào)用的方法、局部變量指針和操作數(shù)棧的棧頂和棧底指針。
? 執(zhí)行環(huán)境是一個(gè)執(zhí)行一個(gè)方法的控制中心。例如:如果解釋器要執(zhí)行iadd(整數(shù)加法),首先要從frame寄存器中找到當(dāng)前執(zhí)行環(huán)境,而后便從執(zhí)行環(huán)境中找到操作數(shù)棧,從棧 ? 頂彈出兩個(gè)整數(shù)進(jìn)行加法運(yùn)算,最后將結(jié)果壓入棧頂。
? 操作數(shù)棧
? 用于存儲(chǔ)運(yùn)算所需操作數(shù)及運(yùn)算的結(jié)果
? (3)jvm 堆
? Java類的實(shí)例所需的存儲(chǔ)空間是在堆上分配的。解釋器負(fù)責(zé)分配,記錄,回收。
? 用于存放類的對(duì)象實(shí)例。
? (4)jvm存儲(chǔ)區(qū),這個(gè)是最重要的,是jvm的軀干。任何數(shù)據(jù)的加載和方法的加載,都是從這個(gè)區(qū)域復(fù)制過去的。
? ?JVM有兩類存儲(chǔ)區(qū):常量緩沖池和方法區(qū)。
? ?常量緩沖池用于存儲(chǔ)類名稱、方法和字段名稱以及串常量。
? ?方法區(qū)。在java的虛擬機(jī)中有一塊專門用來存放已經(jīng)加載的類信息、常量、靜態(tài)變量以及方法代碼的內(nèi)存區(qū)域
? ?方法區(qū)則用于存儲(chǔ)Java方法的字節(jié)碼。
? ?方法區(qū)提供加載的類的存儲(chǔ),也是生命周期最長(zhǎng)的,所以這里面也包含靜態(tài)變量的存儲(chǔ),常量存儲(chǔ)。但是jvm存儲(chǔ)區(qū)還存在一個(gè)緩存區(qū),這個(gè)緩存區(qū)就是加快一些數(shù)據(jù)和信息 ? ? ?的讀取工作,如字段,串常量(把字符串常量放到這里面,可以加快讀取工作)和類名稱。類名稱是必然要放到緩存區(qū)的,這樣可以很好的遍歷尋找類。方法也是如此。就相 ? 當(dāng)于你有一個(gè)很大的數(shù)據(jù)表保存你的信息,但是你還需要一個(gè)索引記錄信息的名稱,關(guān)鍵字等信息,這樣可以提供你盡快從你的較大的數(shù)據(jù)表中讀取你要的數(shù)據(jù)。
?
2.jvm結(jié)構(gòu)圖
3.jvm的類加載器
BootStrap ClassLoader:稱為啟動(dòng)類加載器,是Java類加載層次中最頂層的類加載器,負(fù)責(zé)加載JDK中的核心類庫(kù),如:rt.jar、resources.jar、charsets.jar等,可通過如下程序獲得該類加載器從哪些地方加載了相關(guān)的jar或class文件:
?
這是獲得jdk環(huán)境
System.out.println(System.getProperty("sun.boot.class.path"));這是獲取 根加載器路徑
Extension ClassLoader:稱為擴(kuò)展類加載器,負(fù)責(zé)加載Java的擴(kuò)展類庫(kù),Java 虛擬機(jī)的實(shí)現(xiàn)會(huì)提供一個(gè)擴(kuò)展庫(kù)目錄。該類加載器在此目錄里面查找并加載 Java 類。
默認(rèn)加載JAVA_HOME/jre/lib/ext/目下的所有jar。
App ClassLoader:稱為系統(tǒng)類加載器,負(fù)責(zé)加載應(yīng)用程序classpath目錄下的所有jar和class文件。一般來說,Java 應(yīng)用的類都是由它來完成加載的。可以通過 ClassLoader.getSystemClassLoader()來獲取它。
?
除了系統(tǒng)提供的類加載器以外,開發(fā)人員可以通過繼承java.lang.ClassLoader類的方式實(shí)現(xiàn)自己的類加載器,以滿足一些特殊的需求。
除了引導(dǎo)類加載器之外,所有的類加載器都有一個(gè)父類加載器。 給出的 getParent()方法可以得到。對(duì)于?
系統(tǒng)提供的類加載器來說,系統(tǒng)類加載器的父類加載器是擴(kuò)展類加載器,而擴(kuò)展類加載器的父類加載器是引導(dǎo)類加載器;對(duì)于開發(fā)人員編寫的類加載器來說,其父類加載器是加載此類加載器 Java 類的類加載器。因?yàn)轭惣虞d器 Java 類如同其它的 Java 類一樣,也是要由類加載器來加載的。一般來說,開發(fā)人員編寫的類加載器的父類加載器是系統(tǒng)類加載器。類加載器通過這種方式組織起來,形成樹狀結(jié)構(gòu)。樹的根節(jié)點(diǎn)就是引導(dǎo)類加載器。
4.程序運(yùn)行
PC計(jì)數(shù)器:
每一個(gè)線程都擁有一個(gè)PC計(jì)數(shù)器,當(dāng)線程啟動(dòng)(start)時(shí),PC計(jì)數(shù)器被創(chuàng)建,這個(gè)計(jì)數(shù)器存放當(dāng)前正在被執(zhí)行的字節(jié)碼指令(JVM指令)的地址。
Java棧:
同樣的,Java棧也是每個(gè)線程單獨(dú)擁有,線程啟動(dòng)時(shí)創(chuàng)建。這個(gè)棧中存放著一系列的棧幀(Stack Frame),JVM只能進(jìn)行壓入(Push)和彈出(Pop)棧幀這兩種操作。每當(dāng)調(diào)用一個(gè)方法時(shí),JVM就往棧里壓入一個(gè)棧幀,方法結(jié)束返回時(shí)彈出棧幀。如果方法執(zhí)行時(shí)出現(xiàn)異常,可以調(diào)用printStackTrace等方法來查看棧的情況
5.jvm 底層實(shí)現(xiàn)的數(shù)據(jù)結(jié)構(gòu)?
對(duì)象在堆中的存儲(chǔ)結(jié)構(gòu)是hashtable, 每一個(gè)對(duì)象的hashcode 就是在hash表中查詢的key值。
在常量區(qū)中,所有的類字節(jié)碼文件中的字符信息存儲(chǔ)到方法區(qū)中的常量池中,常量池也是一個(gè)hash表。
在方法區(qū)中類對(duì)象的存儲(chǔ)結(jié)構(gòu)也是hash表,reference堆上面的句柄池也是hash表。
?
總結(jié)
以上是生活随笔為你收集整理的Java虚拟机简单介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果xr红色为什么是特别版(苹果官网报价
- 下一篇: Java object方法与GC回收