JVM淺談

做為java開發(fā)者,平時(shí)工作中打交道最多的就是JVM了办陷,JVM是Java Virtual Machine(Java虛擬機(jī))的縮寫囤热,JVM是一種用于計(jì)算設(shè)備的規(guī)范,它是一個(gè)虛構(gòu)出來(lái)的計(jì)算機(jī)厌殉,是通過(guò)在實(shí)際的計(jì)算機(jī)上仿真模擬各種計(jì)算機(jī)功能來(lái)實(shí)現(xiàn)的。引入Java語(yǔ)言虛擬機(jī)后侈咕,Java語(yǔ)言在不同平臺(tái)上運(yùn)行時(shí)不需要重新編譯公罕。Java語(yǔ)言使用Java虛擬機(jī)屏蔽了與具體平臺(tái)相關(guān)的信息,使得Java語(yǔ)言編譯程序只需生成在Java虛擬機(jī)上運(yùn)行的目標(biāo)代碼(字節(jié)碼)耀销,就可以在多種平臺(tái)上不加修改地運(yùn)行楼眷。

市面上常見(jiàn)的主流JVM虛擬機(jī)有HotSpot VM、J9 VM熊尉、JRockit VM(JDK8中已與HotSpot合并)罐柳、Zing VM等,本文內(nèi)容主要基于HotSpot VM狰住。

JAVA類加載過(guò)程

類加載的過(guò)程包括了加載张吉、驗(yàn)證、準(zhǔn)備催植、解析肮蛹、初始化五個(gè)階段勺择。其中準(zhǔn)備、驗(yàn)證伦忠、解析三個(gè)部分統(tǒng)稱為連接省核。

加載

查找并加載類的二進(jìn)制數(shù)據(jù)按照虛擬機(jī)所需的格式存儲(chǔ)在方法區(qū)之中。

  • 通過(guò)一個(gè)類的全限定名來(lái)獲取其定義的二進(jìn)制字節(jié)流昆码。
  • 將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)芳撒。
  • 在Java堆中生成一個(gè)代表這個(gè)類的 java.lang.Class對(duì)象,作為對(duì)方法區(qū)中這些數(shù)據(jù)的訪問(wèn)入口未桥。

驗(yàn)證

確保Class文件的字節(jié)流中包含的信息符合當(dāng)前虛擬機(jī)的要求笔刹,并且不會(huì)危害虛擬機(jī)自身的安全。

  • 文件格式驗(yàn)證:驗(yàn)證字節(jié)流是否符合Class文件格式的規(guī)范冬耿;例如:是否以 0xCAFEBABE開頭舌菜、主次版本號(hào)是否在當(dāng)前虛擬機(jī)的處理范圍之內(nèi)、常量池中的常量是否有不被支持的類型亦镶。
  • 元數(shù)據(jù)驗(yàn)證:對(duì)字節(jié)碼描述的信息進(jìn)行語(yǔ)義分析(注意:對(duì)比javac編譯階段的語(yǔ)義分析)日月,以保證其描述的信息符合Java語(yǔ)言規(guī)范的要求;例如:這個(gè)類是否有父類缤骨,除了 java.lang.Object之外爱咬。
  • 字節(jié)碼驗(yàn)證:通過(guò)數(shù)據(jù)流和控制流分析,確定程序語(yǔ)義是合法的绊起、符合邏輯的精拟。
  • 符號(hào)引用驗(yàn)證:確保解析動(dòng)作能正確執(zhí)行。

驗(yàn)證階段是非常重要的虱歪,但不是必須的蜂绎,它對(duì)程序運(yùn)行期沒(méi)有影響。如果所引用的類經(jīng)過(guò)反復(fù)驗(yàn)證笋鄙,那么可以考慮采用-Xverifynone參數(shù)來(lái)關(guān)閉大部分的類驗(yàn)證措施师枣,以縮短虛擬機(jī)類加載的時(shí)間。

準(zhǔn)備

正式為類變量(static成員變量)分配內(nèi)存并設(shè)置類變量初始值的階段萧落,這些內(nèi)存都將在方法區(qū)中分配践美。

  • 內(nèi)存分配的僅包括類變量(static),而不包括實(shí)例變量找岖,實(shí)例變量會(huì)在對(duì)象實(shí)例化時(shí)隨著對(duì)象一塊分配在Java堆中陨倡。
  • 初始值通常情況下是數(shù)據(jù)類型的默認(rèn)值(如0、0L宣增、false等)玫膀,不是被在Java代碼中被顯式地賦予的值矛缨。如public static int a = 1 在準(zhǔn)備階段過(guò)后的值為0而不是1爹脾。賦值為1的動(dòng)作將在初始化階段才會(huì)執(zhí)行帖旨。
  • 如果類字段為常量類字段,那么在準(zhǔn)備階段變量值會(huì)被初始化為指定的常量值灵妨。如public static final int a = 1 在準(zhǔn)備階段過(guò)后的值就是1解阅。

解析

解析階段是把常量池內(nèi)的符號(hào)引用替換成直接引用的過(guò)程。包括對(duì)類或接口泌霍、字段货抄、類方法、接口方法朱转、方法類型蟹地、方法句柄和調(diào)用點(diǎn)限定符7類符號(hào)引用進(jìn)行解析。

  • 符號(hào)引用(Symbolic References):符號(hào)引用以一組符號(hào)來(lái)描述所引用的目標(biāo)藤为,符號(hào)可以是任何形式的字面量怪与,只要可以唯一定位到目標(biāo)即可。符號(hào)引用于內(nèi)存布局無(wú)關(guān)缅疟,所以所引用的對(duì)象不一定需要已經(jīng)加載到內(nèi)存中分别。
  • 直接引用(Direct References):直接引用時(shí)直接指向目標(biāo)的指針、相對(duì)偏移量或是一個(gè)能間接定位到目標(biāo)的句柄存淫,有了直接引用耘斩,那么它一定已經(jīng)存在于內(nèi)存中了。

初始化

初始化階段桅咆,才真正開始執(zhí)行類中定義的java程序代碼(字節(jié)碼)括授,為類的靜態(tài)變量賦予正確的初始值。
對(duì)類變量進(jìn)行初始值設(shè)定的方式:

  • 聲明類變量時(shí)指定初始值
  • 使用靜態(tài)代碼塊為類變量指定初始值

靜態(tài)語(yǔ)句塊只能訪問(wèn)到定義在靜態(tài)語(yǔ)句塊之前的變量岩饼,定義在它之后的變量刽脖,在前面的靜態(tài)語(yǔ)句塊可以賦值,但是不能訪問(wèn)

public class Test{
 static{
     a = 0;
    System.out.println(a); // IDE將提示 Illegal forward reference
 }
 static int a = 1;
} 

初始化步驟:

  1. 假如這個(gè)類還沒(méi)有被加載和連接忌愚,則程序先加載并連接該類
  2. 假如該類的直接父類還沒(méi)有被初始化曲管,則先初始化其直接父類
  3. 假如類中有初始化語(yǔ)句,則系統(tǒng)依次執(zhí)行這些初始化語(yǔ)句

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

20201119222821.jpg
  • 程序計(jì)數(shù)器: 一塊較小的內(nèi)存空間硕糊,可以看做是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器院水。
  • jvm棧:即線程棧(每個(gè)線程都有自己的棧),棧幀為加載的每個(gè)方法(入棧操作即方法入棧)或for循環(huán)等;棧用來(lái)保存基本數(shù)據(jù)類型的值,方法內(nèi)對(duì)象的引用(指針)简十,方法參數(shù)引用檬某,常量池引用等。
  • jvm本地方法棧: 針對(duì)Native方法的棧螟蝙。(HotSopt虛擬機(jī)中直接就把本地方法棧和Java棧合二為一)
  • jvm元數(shù)據(jù)空間:存儲(chǔ)class的元數(shù)據(jù)信息恢恼,使用的是Direct Memory,即本地內(nèi)存胰默,默認(rèn)情況下场斑,大小只受可用的本地內(nèi)存限制漓踢。
  • jvm 堆:
    • 新生代:1個(gè)Eden區(qū)和2個(gè)Survivor區(qū)(分別叫From和To)。
      • Eden: 保持著新創(chuàng)建的對(duì)象
      • From:上一次Young GC后的To,保存著每次Young GC后存活的對(duì)象漏隐,每次GC后對(duì)象的年齡會(huì)加1,到一定閾值會(huì)回直接放到老年代喧半,沒(méi)有到達(dá)閾值的放到To Survivor中。
      • To: To Survivor被填滿后會(huì)將對(duì)象一次性移動(dòng)到老年代中青责,然后To和From Survivor區(qū)相互交換挺据。
    • 老年代: 存放的都是一些生命周期較長(zhǎng)的對(duì)象。

JVM垃圾回收算法

所有的垃圾收集算法都面臨同一個(gè)問(wèn)題脖隶,那就是找出應(yīng)用程序不可到達(dá)的內(nèi)存塊扁耐,將其釋放,這里面得不可到達(dá)主要是指應(yīng)用程序已經(jīng)沒(méi)有內(nèi)存塊的引用了产阱,而在JAVA中做葵,某個(gè)對(duì)象對(duì)應(yīng)用程序是可到達(dá)的是指:這個(gè)對(duì)象被根(根主要是指類的靜態(tài)變量,或者活躍在所有線程棧的對(duì)象的引用)引用或者對(duì)象被另一個(gè)可到達(dá)的對(duì)象引用心墅。

  • 復(fù)制算法
    此算法把內(nèi)存空間劃為兩個(gè)相等的區(qū)域酿矢,每次只使用其中一個(gè)區(qū)域。垃圾回收時(shí)怎燥,遍歷當(dāng)前使用區(qū)域瘫筐,把正在使用中的對(duì)象復(fù)制到另外一個(gè)區(qū)域中。此算法每次只處理正在使用中的對(duì)象铐姚,因此復(fù)制成本比較小策肝,同時(shí)復(fù)制過(guò)去以后還能進(jìn)行相應(yīng)的內(nèi)存整理,不會(huì)出現(xiàn)“碎片”問(wèn)題隐绵。當(dāng)然之众,此算法的缺點(diǎn)也是很明顯的,就是需要兩倍內(nèi)存空間依许。
  • 標(biāo)記清除
    此算法執(zhí)行分兩階段棺禾。第一階段從引用根節(jié)點(diǎn)開始標(biāo)記所有被引用的對(duì)象,第二階段遍歷整個(gè)堆峭跳,把未標(biāo)記的對(duì)象清除膘婶。此算法需要暫停整個(gè)應(yīng)用,同時(shí)蛀醉,會(huì)產(chǎn)生內(nèi)存碎片悬襟。
  • 標(biāo)記整理
    此算法結(jié)合了“標(biāo)記-清除”和“復(fù)制”兩個(gè)算法的優(yōu)點(diǎn)。也是分兩階段拯刁,第一階段從根節(jié)點(diǎn)開始標(biāo)記所有被引用對(duì)象脊岳,第二階段遍歷整個(gè)堆,把清除未標(biāo)記對(duì)象并且把存活對(duì)象“壓縮”到堆的其中一塊,按順序排放割捅。此算法避免了“標(biāo)記-清除”的碎片問(wèn)題奶躯,同時(shí)也避免了“復(fù)制”算法的空間問(wèn)題。

jvm中g(shù)c算法 年輕代:復(fù)制算法棺牧; 老年代:標(biāo)記清除巫糙,標(biāo)記整理朗儒。

java對(duì)象內(nèi)存申請(qǐng):

Java堆是被所有線程共享的一塊內(nèi)存區(qū)域颊乘,主要用于存放對(duì)象實(shí)例,在堆上為對(duì)象分配內(nèi)存就是把一塊大小確定的內(nèi)存從堆內(nèi)存中劃分出來(lái)醉锄,將對(duì)象放進(jìn)去乏悄。

  • 指針碰撞法:已分配的內(nèi)存和空閑內(nèi)存分別在不同的一側(cè),通過(guò)一個(gè)指針指向分界點(diǎn)恳不,當(dāng)需要分配內(nèi)存時(shí)檩小,把指針往空閑的一端移動(dòng)與對(duì)象大小相等的距離即可,對(duì)于堆空間是連續(xù)的來(lái)說(shuō)可以直接偏移指針即可烟勋,一般來(lái)說(shuō)采用標(biāo)記整理算法的堆空間是連續(xù)的规求。
  • 空閑列表法:對(duì)于堆空間已分配的內(nèi)存和空閑內(nèi)存相互交錯(cuò)不連續(xù)時(shí)需要由jvm來(lái)維護(hù)一個(gè)“空閑列表”用來(lái)記錄那些區(qū)域內(nèi)存是空閑的。

對(duì)象創(chuàng)建在虛擬機(jī)中是非常頻繁的行為卵惦,即使是僅僅修改一個(gè)指針?biāo)赶虻奈恢米柚祝诓l(fā)情況下也并不是線程安全的,可能出現(xiàn)正在給對(duì)象A分配內(nèi)存沮尿,指針還沒(méi)來(lái)得及修改丛塌,對(duì)象B又同時(shí)使用了原來(lái)的指針來(lái)分配內(nèi)存的情況。解決這個(gè)問(wèn)題有兩種方案:一種是對(duì)分配內(nèi)存空間的動(dòng)作進(jìn)行同步處理——實(shí)際上虛擬機(jī)采用CAS配上失敗重試的方式保證更新操作的原子性,該種方式在并發(fā)較高時(shí)對(duì)CPU時(shí)間片占用較多一般不會(huì)使用畜疾;另一種是把內(nèi)存分配的動(dòng)作按照線程劃分在不同的空間之中進(jìn)行赴邻,即每個(gè)線程在Java堆中預(yù)先分配一小塊內(nèi)存,稱為本地線程分配緩沖(Thread Local Allocation Buffer,TLAB)啡捶。

JVM常用啟動(dòng)參數(shù)及含義

-server:指定jvm以server模式運(yùn)行姥敛;Client模式啟動(dòng)速度較快,Server模式啟動(dòng)較慢瞎暑;但是啟動(dòng)進(jìn)入穩(wěn)定期長(zhǎng)期運(yùn)行之后Server模式的程序運(yùn)行速度比Client要快很多徒溪。
-Xms:初始堆大小
-Xmx:最大堆大小
-Xmn:設(shè)置年輕代大小,不能超過(guò)-Xmx
-Xss:設(shè)置線程棧大小,默認(rèn)為1024KB金顿,對(duì)于高并發(fā)應(yīng)用且線程中存放的局部變量信息不多可降低該值以提高有更多內(nèi)存來(lái)開辟新的線程臊泌。
-XX:NewRatio: 設(shè)置年輕代和年老代的比值。如:為3揍拆,表示年輕代與年老代比值為1:3渠概,年輕代占整個(gè)年輕代年老代和的1/4
-XX:SurvivorRatio: 年輕代中Eden區(qū)與兩個(gè)Survivor區(qū)的比值。注意Survivor區(qū)有兩個(gè)。如:3播揪,表示Eden:Survivor=3:2贮喧,一個(gè)Survivor區(qū)占整個(gè)年輕代的1/5
-XX:MaxMetaspaceSize: 設(shè)置最大元數(shù)據(jù)空間。
-XX:MaxMetaspaceSize: 設(shè)置初始元數(shù)據(jù)空間猪狈。
-XX:+UseConcMarkSweepGC :老年代使用CMS收集器
-XX:CMSInitiatingOccupancyFraction:CMS垃圾收集器箱沦,當(dāng)老年代內(nèi)存使用達(dá)到指定配置比例時(shí),觸發(fā)CMS垃圾回收
-XX:+UseCMSInitiatingOccupancyOnly: 指定HotSpot-VM總是使用-XX:CMSInitiatingOccupancyFraction的值作為old的空間使用率限制來(lái)啟動(dòng)CMS垃圾回收雇庙。如果沒(méi)有使用-XX:+UseCMSInitiatingOccupancyOnly谓形,那么HotSpot-VM只是利用這個(gè)值來(lái)啟動(dòng)第一次CMS垃圾回收,后面都是使用HotSpot-VM自動(dòng)計(jì)算出來(lái)的值疆前。

JVM進(jìn)程正常退出的條件

線程類型

  • 用戶線程:普通線程又可以稱為用戶線程
  • 后臺(tái)線程:執(zhí)行setDaemon(true)的線程寒跳,在后臺(tái)提供一種通用服務(wù)的線程,并且這種線程并不屬于程序中不可或缺的部分竹椒。

當(dāng)不存在用戶線程的時(shí)候童太,JVM進(jìn)程就會(huì)退出。

可能出現(xiàn)FullGC的情況

  • 老年代被寫滿
  • 元數(shù)據(jù)空間超過(guò)設(shè)置 -XX:MaxMetaspaceSize時(shí)
  • System.gc()被顯示調(diào)用
  • 上一次GC之后Heap的各域分配策略動(dòng)態(tài)變化

Minor胸完、Young书释、Major GC的區(qū)別

73230d3cdceb46300d51f8aaf5f262d3eca.jpg
  • Minor GC發(fā)生在Eden區(qū)
  • Young GC發(fā)生在Eden、Survivor0赊窥、Survivor1區(qū)
  • Major GC發(fā)生在Old區(qū)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末爆惧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子誓琼,更是在濱河造成了極大的恐慌检激,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腹侣,死亡現(xiàn)場(chǎng)離奇詭異叔收,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)傲隶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門饺律,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人跺株,你說(shuō)我怎么就攤上這事复濒。” “怎么了乒省?”我有些...
    開封第一講書人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵巧颈,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我袖扛,道長(zhǎng)砸泛,這世上最難降的妖魔是什么十籍? 我笑而不...
    開封第一講書人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮唇礁,結(jié)果婚禮上勾栗,老公的妹妹穿的比我還像新娘。我一直安慰自己盏筐,他們只是感情好围俘,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著琢融,像睡著了一般界牡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吏奸,一...
    開封第一講書人閱讀 52,736評(píng)論 1 312
  • 那天欢揖,我揣著相機(jī)與錄音陶耍,去河邊找鬼奋蔚。 笑死,一個(gè)胖子當(dāng)著我的面吹牛烈钞,可吹牛的內(nèi)容都是我干的泊碑。 我是一名探鬼主播,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼毯欣,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼馒过!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起酗钞,我...
    開封第一講書人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤腹忽,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后砚作,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體窘奏,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年葫录,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了着裹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡米同,死狀恐怖骇扇,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情面粮,我是刑警寧澤少孝,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站熬苍,受9級(jí)特大地震影響稍走,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一钱磅、第九天 我趴在偏房一處隱蔽的房頂上張望梦裂。 院中可真熱鬧,春花似錦盖淡、人聲如沸年柠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)冗恨。三九已至,卻和暖如春味赃,著一層夾襖步出監(jiān)牢的瞬間掀抹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工心俗, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留傲武,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓城榛,卻偏偏與公主長(zhǎng)得像揪利,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子狠持,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 前言 由于先前也遇到過(guò)一些性能問(wèn)題疟位,OOM算是其中的一大類了。因此也對(duì)jvm產(chǎn)生了一些興趣喘垂。自己對(duì)jvm略做了...
    betterFighter閱讀 313評(píng)論 0 1
  • 前言 由于先前也遇到過(guò)一些性能問(wèn)題甜刻,OOM算是其中的一大類了。因此也對(duì)jvm產(chǎn)生了一些興趣正勒。自己對(duì)jvm略做了些研...
    betterFighter閱讀 208評(píng)論 0 0
  • 一.數(shù)據(jù)類型 java虛擬機(jī)中得院,數(shù)據(jù)類型可以分為兩類:基本類型和引用類型≌哑耄基本類型的變量保存原始值尿招,即:它代表的值...
    Java架構(gòu)007閱讀 218評(píng)論 0 1
  • 作者:一字馬胡 轉(zhuǎn)載標(biāo)志 【2017-11-12】 更新日志 日期更新內(nèi)容備注 2017-11-12新建文章初版 ...
    beneke閱讀 2,211評(píng)論 0 7
  • 寫在前面 簡(jiǎn)單的介紹一下JVM(Java Virtual Machine)吧,它也叫Java虛擬機(jī)阱驾。雖然它叫虛擬機(jī)...
    SH的全棧筆記閱讀 204評(píng)論 0 0