1.什么是jvm?
(1)jvm是一種用于計算設(shè)備的規(guī)范,它是一個虛構(gòu)出來的機(jī)器在抛,是通過在實際的計算機(jī)上仿真模擬各種功能實現(xiàn)的褥伴。
(2) jvm包含一套字節(jié)碼指令集,一組寄存器逮走,一個棧鸠蚪,一個垃圾回收堆和一個存儲方法域。
(3) JVM屏蔽了與具體操作系統(tǒng)平臺相關(guān)的信息师溅,使Java程序只需生成在Java虛擬機(jī)上運行的目標(biāo)代碼(字節(jié)碼),就可以在多種平臺上不加修改地運行茅信。JVM在執(zhí)行字節(jié)碼時,實際上最終還是把字節(jié)碼解釋成具體平臺上的機(jī)器指令執(zhí)行险胰。
2.jdk汹押、jre、jvm是什么關(guān)系起便?
(1)JRE(Java Runtime Environment)棚贾,也就是java平臺。所有的java程序都要在JRE環(huán)境下才能運行榆综。
(2)JDK(Java Development Kit)妙痹,是開發(fā)者用來編譯、調(diào)試程序用的開發(fā)包鼻疮。JDK也是JAVA程序需要在JRE上運行怯伊。
(3)JVM(Java Virtual Machine),是JRE的一部分判沟。它是一個虛構(gòu)出來的計算機(jī)耿芹,是通過在實際的計算機(jī)上仿真模擬各種計算機(jī)功能來實現(xiàn)的。
JVM有自己完善的硬件架構(gòu)挪哄,如處理器吧秕、堆棧、寄存器等迹炼,還具有相應(yīng)的指令系統(tǒng)砸彬。
Java語言最重要的特點就是跨平臺運行。使用JVM就是為了支持與操作系統(tǒng)無關(guān)斯入,實現(xiàn)跨平臺砂碉。
3.JVM原理
(1)jvm是java的核心和基礎(chǔ),在java編譯器和os平臺之間的虛擬處理器刻两,可在上面執(zhí)行字節(jié)碼程序增蹭。
(2)java編譯器只要面向jvm,生成jvm能理解的字節(jié)碼文件闹伪。java源文件經(jīng)編譯成字節(jié)碼程序沪铭,通過jvm將每條指令翻譯成不同的機(jī)器碼,通過特定平臺運行
image.png
4. JVM執(zhí)行程序的過程
1.加載.class文件
2.管理并分配內(nèi)存
3.執(zhí)行垃圾收集
4.JRE(java運行時環(huán)境)由JVM構(gòu)造的java程序的運行環(huán)壮池,也是Java程序運行的環(huán)境,但是他同時一個操作系統(tǒng)的一個應(yīng)用程序一個進(jìn)程杀怠,
因此他也有他自己的運行的生命周期椰憋,也有自己的代碼和數(shù)據(jù)空間。
JVM在整個jdk中處于最底層赔退,負(fù)責(zé)于操作系統(tǒng)的交互橙依,用來屏蔽操作系統(tǒng)環(huán)境,
提供一個完整的Java運行環(huán)境硕旗,因此也就虛擬計算機(jī)窗骑。
5.JVM的生命周期
JVM實例對應(yīng)了一個獨立運行的java程序它是進(jìn)程級別
a) 啟動。啟動一個Java程序時漆枚,一個JVM實例就產(chǎn)生了创译,任何一個擁有public static void main(String[] args)函數(shù)的class都可以作為JVM實例運行的起點
b) 運行。main()作為該程序初始線程的起點墙基,任何其他線程均由該線程啟動软族。JVM內(nèi)部有兩種線程:守護(hù)線程和非守護(hù)線程,main()屬于非守護(hù)線程残制,守護(hù)線程通常由JVM自己使用立砸,java程序也可以表明自己創(chuàng)建的線程是守護(hù)線程
c) 消亡。當(dāng)程序中的所有非守護(hù)線程都終止時初茶,JVM才退出颗祝;若安全管理器允許,程序也可以使用Runtime類或者System.exit()來退出
JVM執(zhí)行引擎實例則對應(yīng)了屬于用戶運行程序的線程它是線程級別的
6.JVM內(nèi)存模型
(1)java代碼具體執(zhí)行過程如下圖:
(2)運行時數(shù)據(jù)區(qū)恼布,即jvm內(nèi)存結(jié)構(gòu)圖如下圖:
(3)運行時數(shù)據(jù)區(qū)存儲了哪些數(shù)據(jù)螺戳?
a) 程序計數(shù)器(PC寄存器)
由于在JVM中,多線程是通過線程輪流切換來獲得CPU執(zhí)行時間的折汞,因此温峭,在任一具體時刻,一個CPU的內(nèi)核只會執(zhí)行一條線程中的指令,因此字支,為了能夠使得每個線程都在線程切換后能夠恢復(fù)在切換之前的程序執(zhí)行位置,每個線程都需要有自己獨立的程序計數(shù)器奸忽,并且不能互相被干擾堕伪,否則就會影響到程序的正常執(zhí)行次序。因此栗菜,可以這么說欠雌,程序計數(shù)器是每個線程所私有的。由于程序計數(shù)器中存儲的數(shù)據(jù)所占空間的大小不會隨程序的執(zhí)行而發(fā)生改變疙筹,因此富俄,對于程序計數(shù)器是不會發(fā)生內(nèi)存溢出現(xiàn)象(OutOfMemory)的禁炒。
b)Java棧
Java棧中存放的是一個個的棧幀,每個棧幀對應(yīng)一個被調(diào)用的方法霍比,在棧幀中包括局部變量表(Local Variables)幕袱、操作數(shù)棧(Operand Stack)、指向當(dāng)前方法所屬的類的運行時常量池(運行時常量池的概念在方法區(qū)部分會談到)的引用(Reference to runtime constant pool)悠瞬、方法返回地址(Return Address)和一些額外的附加信息们豌。當(dāng)線程執(zhí)行一個方法時,就會隨之創(chuàng)建一個對應(yīng)的棧幀浅妆,并將建立的棧幀壓棧望迎。當(dāng)方法執(zhí)行完畢之后,便會將棧幀出棧凌外。
image.png
c)本地方法棧
本地方法棧與Java棧的作用和原理非常相似辩尊。區(qū)別只不過是Java棧是為執(zhí)行Java方法服務(wù)的,而本地方法棧則是為執(zhí)行本地方法(Native Method)服務(wù)的
d)堆
Java中的堆是用來存儲對象本身的以及數(shù)組(數(shù)組引用是存放在Java棧中的)康辑。堆是被所有線程共享的摄欲,在JVM中只有一個堆。
e)方法區(qū)
與堆一樣晾捏,是被線程共享的區(qū)域蒿涎。在方法區(qū)中,存儲了每個類的信息(包括類的名稱惦辛、方法信息劳秋、字段信息)、靜態(tài)變量胖齐、常量以及編譯器編譯后的代碼等玻淑。
在Class文件中除了類的字段、方法呀伙、接口等描述信息外补履,還有一項信息是常量池,用來存儲編譯期間生成的字面量和符號引用剿另。
在方法區(qū)中有一個非常重要的部分就是運行時常量池箫锤,它是每一個類或接口的常量池的運行時表示形式,在類和接口被加載到JVM后雨女,
對應(yīng)的運行時常量池就被創(chuàng)建出來谚攒。當(dāng)然并非Class文件常量池中的內(nèi)容才能進(jìn)入運行時常量池,在運行期間也可將新的常量放入運行時常量池中氛堕,比如String的intern方法馏臭。
7.Java內(nèi)存溢出的情況
a) 程序計數(shù)器(Program Counter Register)
每條線程都有一個獨立的的程序計數(shù)器,各線程間的計數(shù)器互不影響讼稚,因此該區(qū)域是線程私有的括儒。該內(nèi)存區(qū)域是唯一一個在Java虛擬機(jī)規(guī)范中沒有規(guī)定任何OOM(內(nèi)存溢出:OutOfMemoryError)情況的區(qū)域绕沈。
b)Java虛擬機(jī)棧(Java Virtual Machine Stacks)
在Java虛擬機(jī)規(guī)范中,對這個區(qū)域規(guī)定了兩種異常情況:
1.如果線程請求的棧深度大于虛擬機(jī)所允許的深度帮寻,將拋出StackOverflowError異常乍狐。
2.如果虛擬機(jī)在動態(tài)擴(kuò)展棧時無法申請到足夠的內(nèi)存空間,則拋出OutOfMemoryError異常规婆。
在單線程的操作中澜躺,無論是由于棧幀太大,還是虛擬機(jī)検阊粒空間太小掘鄙,當(dāng)棧空間無法分配時嗡髓,虛擬機(jī)拋出的都是StackOverflowError異常操漠,而不會得到OutOfMemoryError異常。而在多線程環(huán)境下饿这,則會拋出OutOfMemoryError異常浊伙。
c)堆Java Heap
Java Heap是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊,它是所有線程共享的一塊內(nèi)存區(qū)域长捧。幾乎所有的對象實例和數(shù)組都在這類分配內(nèi)存嚣鄙。Java Heap是垃圾收集器管理的主要區(qū)域,因此很多時候也被稱為“GC堆”串结。
d)方法區(qū)域哑子,又被稱為“永久代”,當(dāng)方法區(qū)無法滿足內(nèi)存分配需求時肌割,將拋出OutOfMemoryError異常卧蜓。