柚子快報邀請碼778899分享:1、jvm基礎(chǔ)知(一)
柚子快報邀請碼778899分享:1、jvm基礎(chǔ)知(一)
什么是JVM?
1、定義:JVM 指的是Java虛擬機(jī)( Java Virtual Machine )。JVM 本質(zhì)上是一個運(yùn)行在計算機(jī)上的程序, 他的職責(zé)是運(yùn)行Java字節(jié)碼文件,Java虛擬機(jī)上可以運(yùn)行Java、Kotlin、Scala、Groovy等語言 任務(wù)管理器中啟動的Java進(jìn)程,其實(shí)是一個虛擬機(jī)進(jìn)程,它會執(zhí)行我們編寫好的代碼 2、作用:為了支持Java中Write Once,Run Anywhere;編寫一次,到處運(yùn)行的跨平臺特性。 3、JVM的功能 5、常見的JVM 總結(jié): 1、JVM 指的是Java虛擬機(jī),本質(zhì)上是一個運(yùn)行在計算機(jī)上的程序,他的職 責(zé)是運(yùn)行Java字節(jié)碼文件,作用是為了支持跨平臺特性。 2、JVM的功能有三項:第一是解釋執(zhí)行字節(jié)碼指令;第二是管理內(nèi)存中對象的 分配,完成自動的垃圾回收;第三是優(yōu)化熱點(diǎn)代碼提升執(zhí)行效率。 3、JVM組成分為類加載子系統(tǒng)、運(yùn)行時數(shù)據(jù)區(qū)、執(zhí)行引擎、本地接口這四部分 。 4、常用的JVM是Oracle提供的Hotspot虛擬機(jī),也可以選擇GraalVM、龍井、 OpenJ9等虛擬機(jī)。
了解過字節(jié)碼文件的組成嗎?
字節(jié)碼文件本質(zhì)上是一個二進(jìn)制的文件,無 法直接用記事本等工具打開閱讀其內(nèi)容。需 要通過專業(yè)的工具打開。 ① 開發(fā)環(huán)境使用jclasslib插件 ② 服務(wù)器環(huán)境使用javap –v命令
說一下運(yùn)行時數(shù)據(jù)區(qū)
運(yùn)行時數(shù)據(jù)區(qū)指的是JVM所管理的內(nèi)存區(qū)域,其中分成兩大類: 線程共享 – 方法區(qū)、堆 線程不共享 – 本地方法棧、虛擬機(jī)棧、程序計數(shù)器 直接內(nèi)存主要是NIO使用,由操作系統(tǒng)直接管理,不屬于JVM內(nèi)存
程序計數(shù)器
程序計數(shù)器(Program Counter Register)也叫PC寄存器,每個線程會通過程序計數(shù)器記錄當(dāng)前要執(zhí)行的的字節(jié)碼 指令的地址。主要有兩個作用: 1、程序計數(shù)器可以控制程序指令的進(jìn)行,實(shí)現(xiàn)分支、跳轉(zhuǎn)、異常等邏輯 程序計數(shù)器(Program Counter Register)也叫PC寄存器,每個線程會通過程序計數(shù)器記錄當(dāng)前要執(zhí)行的的字節(jié)碼 指令的地址。主要有兩個作用: 1、程序計數(shù)器可以控制程序指令的進(jìn)行,實(shí)現(xiàn)分支、跳轉(zhuǎn)、異常等邏輯。 2、在多線程執(zhí)行情況下,Java虛擬機(jī)需要通過程序計數(shù)器記錄CPU切換前解釋執(zhí)行到那一句指令并繼續(xù)解釋運(yùn)行。
棧 - Java虛擬機(jī)棧
Java虛擬機(jī)棧采用棧的數(shù)據(jù)結(jié)構(gòu)來管理方法調(diào)用中的基本數(shù)據(jù),先進(jìn)后出 ,每一個方法的調(diào)用使用一個棧幀來保存。 每個線程都會包含一個自己的虛擬機(jī)棧,它的生命周期和線程相同。 棧幀主要包含三部分內(nèi)容: 1、局部變量表,在方法執(zhí)行過程中存放所有的局部變量。 2、操作數(shù)棧,虛擬機(jī)在執(zhí)行指令過程中用來存放臨時數(shù)據(jù)的一塊區(qū)域。 3、幀數(shù)據(jù),主要包含動態(tài)鏈接、方法出口、異常表等內(nèi)容。 動態(tài)鏈接:方法中要用到其他類的屬性和方法,這些內(nèi)容在字節(jié)碼文件中是以編號保存的,運(yùn)行過程中需要替換成 內(nèi)存中的地址,這個編號到內(nèi)存地址的映射關(guān)系就保存在動態(tài)鏈接中。 方法出口:方法調(diào)用完需要彈出棧幀,回到上一個方法,程序計數(shù)器要切換到上一個方法的地址繼續(xù)執(zhí)行,方法出 口保存的就是這個地址。 異常表:存放的是代碼中異常的處理信息,包含了異常捕獲的生效范圍以及異常發(fā)生后跳轉(zhuǎn)到的字節(jié)碼指令位置
本地方法棧
? Java虛擬機(jī)棧存儲了Java方法調(diào)用時的棧幀,而本地方法棧存儲的是native本地方法的棧幀。 ? 在Hotspot虛擬機(jī)中,Java虛擬機(jī)棧和本地方法棧實(shí)現(xiàn)上使用了同一個??臻g。本地方法棧會在棧內(nèi) 存上生成一個棧幀,臨時保存方法的參數(shù)同時方便出現(xiàn)異常時也把本地方法的棧信息打印出來
堆
? 一般Java程序中堆內(nèi)存是空間最大的一塊內(nèi)存區(qū)域。創(chuàng)建出來的對象都存在于堆上。 ? 棧上的局部變量表中,可以存放堆上對象的引用。靜態(tài)變量也可以存放堆對象的引用,通過靜態(tài)變量就可以實(shí) 現(xiàn)對象在線程之間共享。 ? 堆是垃圾回收最主要的部分,堆結(jié)構(gòu)更詳細(xì)的劃分與垃圾回收器有關(guān)。
方法區(qū)
方法區(qū)是Java虛擬機(jī)規(guī)范中提出來的一個虛擬機(jī)概念,在HotSpot不同版本中會用永久代或者元空間來實(shí)現(xiàn)。方法 區(qū)主要存放的是基礎(chǔ)信息,包含: 1、每一個加載的類的元信息(基礎(chǔ)信息)。 2、運(yùn)行時常量池,保存了字節(jié)碼文件中的常量池內(nèi)容,避免常量內(nèi)容重復(fù)創(chuàng)建減少內(nèi)存開銷。 3、字符串常量池,存儲字符串的常量 直接內(nèi)存 直接內(nèi)存并不在《Java虛擬機(jī)規(guī)范》中存在,所以并不屬于Java運(yùn)行時的內(nèi)存區(qū)域。在 JDK 1.4 中引入了 NIO 機(jī) 制,由操作系統(tǒng)直接管理這部分內(nèi)容,主要為了提升讀寫數(shù)據(jù)的性能。在網(wǎng)絡(luò)編程框架如Netty中被大量使用。 要創(chuàng)建直接內(nèi)存上的數(shù)據(jù),可以使用ByteBuffer。 語法: ByteBuffer directBuffer = ByteBuffer.allocateDirect(size);
什么是運(yùn)行時數(shù)據(jù)區(qū)?
運(yùn)行時數(shù)據(jù)區(qū)指的是JVM所管理的內(nèi)存區(qū)域,其中分成兩大類: 線程共享 – 方法區(qū)、堆 方法區(qū):存放每一個加載的類的元信息、運(yùn)行時常量池、字符串常量池。 堆:存放創(chuàng)建出來的對象。 線程不共享 – 本地方法棧、虛擬機(jī)棧、程序計數(shù)器 本地方法棧和虛擬機(jī)棧都存放了線程中執(zhí)行方法時需要使用的基礎(chǔ)數(shù)據(jù)。 程序計數(shù)器存放了當(dāng)前線程執(zhí)行的字節(jié)碼指令在內(nèi)存中的地址。 直接內(nèi)存主要是NIO使用,由操作系統(tǒng)直接管理,不屬于JVM內(nèi)存。
哪些區(qū)域會出現(xiàn)內(nèi)存溢出,會有什么現(xiàn)象?
內(nèi)存溢出指的是內(nèi)存中某一塊區(qū)域的使用量超過了允許使用的最大值,從而使用內(nèi)存時因空間不足而失敗,虛擬機(jī)一般 會拋出指定的錯誤。 在Java虛擬機(jī)中,只有程序計數(shù)器不會出現(xiàn)內(nèi)存溢出的情況,因?yàn)槊總€線程的程序計數(shù)器只保存一個固定長度的地址。 堆內(nèi)存溢出: 堆內(nèi)存溢出指的是在堆上分配的對象空間超過了堆的最大大小,從而導(dǎo)致的內(nèi)存溢出。堆的最大大小使用-Xmx參數(shù)進(jìn) 行設(shè)置,如-Xmx10m代表最大堆內(nèi)存大小為10m。 溢出之后會拋出OutOfMemoryError,并提示是Java heap Space導(dǎo)致的: 棧內(nèi)存溢出: 棧內(nèi)存溢出指的是所有棧幀空間的占用內(nèi)存超過了最大值,最大值使用-Xss進(jìn)行設(shè)置,比如-Xss256k代表所有棧幀占用 內(nèi)存大小加起來不能超過256k。 溢出之后會拋出StackOverflowError: 方法區(qū)內(nèi)存溢出: 方法區(qū)內(nèi)存溢出指的是方法區(qū)中存放的內(nèi)容比如類的元信息超過了方法區(qū)內(nèi)存的最大值,JDK7及之前版本方法區(qū)使用永 久代(-XX:MaxPermSize=值)來實(shí)現(xiàn),JDK8及之后使用元空間(-XX:MaxMetaspaceSize=值)來實(shí)現(xiàn)。 元空間溢出: 永久代溢出: 直接內(nèi)存溢出: 直接內(nèi)存溢出指的是申請的直接內(nèi)存空間大小超過了最大值,使用 -XX:MaxDirectMemorySize=值 設(shè)置最大值。 溢出之后會拋出OutOfMemoryError:
哪些區(qū)域會出現(xiàn)內(nèi)存溢出,會有什么現(xiàn)象?
內(nèi)存溢出指的是內(nèi)存中某一塊區(qū)域的使用量超過了允許使用的最大值,從而使用內(nèi)存 時因空間不足而失敗,虛擬機(jī)一般會拋出指定的錯誤。 堆:溢出之后會拋出OutOfMemoryError,并提示是Java heap Space導(dǎo)致的。 棧:溢出之后會拋出StackOverflowError。 方法區(qū):溢出之后會拋出OutOfMemoryError,JDK7及之前提示永久代,JDK8及之 后提示元空間。 直接內(nèi)存:溢出之后會拋出OutOfMemoryError。
JVM在JDK6-8之間在內(nèi)存區(qū)域上有什么不同 – 方法區(qū)的實(shí)現(xiàn)
? 方法區(qū)是《Java虛擬機(jī)規(guī)范》中設(shè)計的虛擬概念,每款Java虛擬機(jī)在實(shí)現(xiàn)上都各不相同。Hotspot設(shè)計如下: ? JDK7及之前的版本將方法區(qū)存放在堆區(qū)域中的永久代空間,堆的大小由虛擬機(jī)參數(shù)來控制。 ? JDK8及之后的版本將方法區(qū)存放在元空間中,元空間位于操作系統(tǒng)維護(hù)的直接內(nèi)存中,默認(rèn)情況下只要不 超過操作系統(tǒng)承受的上限,可以一直分配。也可以手動設(shè)置最大大小。 使用元空間替換永久代的原因: 1、提高內(nèi)存上限:元空間使用的是操作系統(tǒng)內(nèi)存,而不是JVM內(nèi)存。如果不設(shè)置上限,只要不超過操作系統(tǒng)內(nèi)存 上限,就可以持續(xù)分配。而永久代在堆中,可使用的內(nèi)存上限是有限的。所以使用元空間可以有效減少OOM情況 的出現(xiàn)。 2、優(yōu)化垃圾回收的策略:永久代在堆上,垃圾回收機(jī)制一般使用老年代的垃圾回收方式,不夠靈活。使用元空間 之后單獨(dú)設(shè)計了一套適合方法區(qū)的垃圾回收機(jī)制。
JVM在JDK6-8之間在內(nèi)存區(qū)域上有什么不同 – 字符串常量池的位置
早期設(shè)計時,字符串常量池是屬于運(yùn)行時常量池的一部分,他們存儲的位置也是一致的。后續(xù)做出了調(diào)整, 將字符串常量池和運(yùn)行時常量池做了拆分。
字符串常量池從方法區(qū)移動到堆的原因: 1、垃圾回收優(yōu)化:字符串常量池的回收邏輯和對象的回收邏輯類似,內(nèi)存不足的情況下,如果字符串常量池中的 常量不被使用就可以被回收;方法區(qū)中的類的元信息回收邏輯更復(fù)雜一些。移動到堆之后,就可以利用對象的垃圾 回收器,對字符串常量池進(jìn)行回收。 2、讓方法區(qū)大小更可控:一般在項目中,類的元信息不會占用特別大的空間,所以會給方法區(qū)設(shè)置一個比較小的 上限。如果字符串常量池在方法區(qū)中,會讓方法區(qū)的空間大小變得不可控。 3、intern方法的優(yōu)化:JDK6版本中intern () 方法會把第一次遇到的字符串實(shí)例復(fù)制到永久代的字符串常量 池中。JDK7及之后版本中由于字符串常量池在堆上,就可以進(jìn)行優(yōu)化:字符串保存在堆上,把字符串的引用放入 字符串常量池,減少了復(fù)制的操作。
不同JDK版本之間運(yùn)行時數(shù)據(jù)區(qū)域的區(qū)別是什么? JDK6
不同JDK版本之間運(yùn)行時數(shù)據(jù)區(qū)域的區(qū)別是什么? JDK7
不同JDK版本之間運(yùn)行時數(shù)據(jù)區(qū)域的區(qū)別是什么? JDK8
柚子快報邀請碼778899分享:1、jvm基礎(chǔ)知(一)
推薦鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。