0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

一文讀懂JVM是什么

冬至配餃子 ? 來源:極術(shù)社區(qū) ? 作者:betterFighter ? 2022-07-28 15:36 ? 次閱讀

前言

由于先前也遇到過一些性能問題,OOM算是其中的一大類了。因此也對jvm產(chǎn)生了一些興趣。自己對jvm略做了些研究。后續(xù)繼續(xù)補(bǔ)充。

從oom引申出去

既然說到oom,首先需要知道oom的原因是什么。為啥會oom嘞?
oom的定義是outofmemory。當(dāng)內(nèi)存想為對象分配內(nèi)存的時候,發(fā)現(xiàn)內(nèi)存不足以去分配內(nèi)存,或者gc的時候發(fā)現(xiàn)沒有可以被回收的對象或回收后的內(nèi)存也不足以為對象分配內(nèi)存。

因此拋出這個java異常。

oom
可以分為以下四類

1.堆溢出:java堆

2.棧溢出:虛擬機(jī)棧和本地方法棧

3.方法區(qū)內(nèi)存溢出:方法區(qū)和內(nèi)存時常量池

4.本機(jī)直接內(nèi)存溢出

因此,需要先了解堆,棧,方法區(qū)都是些啥

運(yùn)行時數(shù)據(jù)區(qū)

先上圖

poYBAGLiO6-AYRh8AABaoIqp-Dk913.png

程序計數(shù)器:當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器。

java虛擬機(jī)的多線程是通過輪流切換線程,并為線程分配執(zhí)行時間片去運(yùn)行來執(zhí)行的。每個線程都有一個自己的程序計數(shù)器。我覺得這個可以這么理解:當(dāng)一個線程在運(yùn)行的時候,每執(zhí)行一步程序計數(shù)器都會有個記錄,記錄當(dāng)前執(zhí)行到哪一步了。如果線程被切換后又切換回來,那么通過程序計數(shù)器就能知道執(zhí)行到哪一步了,然后繼續(xù)向下執(zhí)行。

虛擬機(jī)棧:每個線程都會有一個虛擬機(jī)棧。虛擬機(jī)棧描述的是java方法執(zhí)行的內(nèi)存模型。因為線程執(zhí)行的過程就是執(zhí)行線程里的一個個方法,而每個方法都會創(chuàng)建對應(yīng)自己的棧幀。

棧幀里存的內(nèi)容如下:

局部變量表:存放了各種編譯期可知基本數(shù)據(jù)類型,對象引用(引用指針或句柄)

操作數(shù)棧:大多數(shù)指令都要從這里彈出數(shù)據(jù),執(zhí)行運(yùn)算,然后把結(jié)果壓回操作數(shù)棧

動態(tài)鏈接

方法出口

64位的long和都double類型數(shù)據(jù)占用2個局部變量空間,其他數(shù)據(jù)類型占用一個,也就是每個局部變量空間為32位。

在這個地方,如果線程請求的深度大于虛擬機(jī)允許的深度,會拋出StackOverflowError.因為jvm分配給虛擬機(jī)棧的內(nèi)存是有限的,而每個方法都會有對應(yīng)的棧幀壓入到棧中,如果調(diào)用方法過多,那么棧滿了自然也就溢出了。(可能的場景:死循環(huán)代碼,大量遞歸調(diào)用,那排查問題的時候也可以由此有一個思路)??梢酝ㄟ^調(diào)整-Xss去調(diào)整棧大小。

大部分java虛擬機(jī)允許動態(tài)擴(kuò)展,但如果擴(kuò)展的時候也申請不到足夠內(nèi)存時,就會報OOM了。

本地方法棧:和虛擬機(jī)發(fā)揮作用相似。區(qū)別:虛擬機(jī)棧為虛擬機(jī)執(zhí)行java方法服務(wù),本地方法棧為虛擬機(jī)使用的Native方法服務(wù)。Native Method就是一個java調(diào)用非java代碼的接口,Native方法的實(shí)現(xiàn)由非java語言實(shí)現(xiàn)。讀者不用糾結(jié),略作了解即可。

:堆是所有線程共享的一塊內(nèi)存,作用是存放對象實(shí)例。堆可以分為新生代和老年代。新生代里還可細(xì)分為Eden,From survivor,To survivor等空間。后面講述GC過程時會說到。

方法區(qū):也是所有線程共享的一塊內(nèi)存,存放被虛擬機(jī)加載的類信息,常量,靜態(tài)變量,編譯器編譯后的代碼。也就是常說的永久代。

永久代的大小可以用-XX:MaxPermSize去設(shè)置。

運(yùn)行時常量池:方法區(qū)的一部分。存放編譯期生成的各種字面量和符號引用。字面量就是指這個量本身。比如字面量2,就是指2.

運(yùn)行時常量池有一個重要特性就是動態(tài)性。常量不一定只有編譯期才能產(chǎn)生,運(yùn)行期間也可能將新的常量放入常量池。詳情可見String類的

intern()方法。

直接內(nèi)存:它不是虛擬機(jī)運(yùn)行時數(shù)據(jù)區(qū)的一部分,但也頻繁的被使用。直接內(nèi)存不會受到j(luò)ava堆大小的限制,但是會受到本機(jī)總內(nèi)存的限制。

GC過程

GC分為新生代GC(minor gc)和老年代GC(full gc)。新生代GC的頻率遠(yuǎn)遠(yuǎn)高于老年代。而且

新生代GC的速度會比老年代的GC速度快10倍以上。根源在于新生代和老年代使用的GC算法不同。讀者們可以去仔細(xì)思考下(答案文中有,哈哈)。新生代/老年代大小默認(rèn)為1:2。

新生代GC過程

新生代里可細(xì)分為Eden,From survivor,To survivor等空間。當(dāng)我們需要給對象分配內(nèi)存的時候,首先我們會在Eden區(qū)為對象分配內(nèi)存,當(dāng)Eden區(qū)內(nèi)存不足時,會發(fā)生minor gc,此時會把仍然存活的對象放到From survivor,并給對象標(biāo)記存活次數(shù)1;然后當(dāng)Eden區(qū)再次被用完后,對Eden區(qū)和From survivor區(qū)篩選出存活的對象,放到To survivor區(qū),清空Eden區(qū)和From survivor區(qū),存活次數(shù)加1,之前存活的就是2了。

以此類推,默認(rèn)是當(dāng)存活次數(shù)到達(dá)15次(可配置)的時候,把這個對象存入老年代中。同時也可以看到,F(xiàn)rom survivor,To survivor區(qū)始終有一個是空置的。所以新生代使用的只有9/10的空間。
然而大家可以思考一下。Eden區(qū)和survivor區(qū)的大小為8:1,那么發(fā)生minor gc后如果存活的對象
的大小比survivor區(qū)還要大。這個時候會怎么處理?

這里需要引入一個叫“內(nèi)存分配擔(dān)保機(jī)制”的概念。就是當(dāng)存活的對象連survivor區(qū)都放不下的時候,這部分放不下的對象會直接進(jìn)入老年代。老年代是擔(dān)保人。老年代進(jìn)行擔(dān)保,前提是老年代還有剩余空間。但是每次存活下來的對象大小是不確定的。所以只好取之前每次存儲到老年代的對象大小的平均值。如果大于平均值,那么直接full gc。但是為了避免頻繁full gc,仍然會開啟handlepromotionfailure配置。如下圖

poYBAGLiO9SAQQccAAAYbuaIYlY922.png

老年代GC過程

老年代采用了標(biāo)記整理,標(biāo)記清楚的算法。老年代會把仍然存活的對象都整理統(tǒng)一放到一邊。整理完成后就會清楚掉邊界外的對象。這樣就避免了產(chǎn)生大量的內(nèi)存碎片的問題。但是整理算法相較于新生代采用的復(fù)制算法,復(fù)雜程度肯定更高。這也導(dǎo)致了full gc的速度要遠(yuǎn)遠(yuǎn)慢于minor gc。


審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • JAVA
    +關(guān)注

    關(guān)注

    19

    文章

    2948

    瀏覽量

    104391
  • 計數(shù)器
    +關(guān)注

    關(guān)注

    32

    文章

    2248

    瀏覽量

    94197
  • 虛擬機(jī)
    +關(guān)注

    關(guān)注

    1

    文章

    900

    瀏覽量

    27981
  • 內(nèi)存溢出
    +關(guān)注

    關(guān)注

    0

    文章

    10

    瀏覽量

    1187
收藏 人收藏

    評論

    相關(guān)推薦

    讀懂新能源汽車的功能安全

    電子發(fā)燒友網(wǎng)站提供《讀懂新能源汽車的功能安全.pdf》資料免費(fèi)下載
    發(fā)表于 09-04 09:22 ?2次下載

    從原理聊JVM):染色標(biāo)記和垃圾回收算法

    導(dǎo)讀 JAVA簡單易用的特性,能夠讓研發(fā)人員在不了解JVM的底層運(yùn)行機(jī)制的情況下依舊能夠編寫出功能完善的代碼。 但是對JVM的理解,是個程序員普通和優(yōu)秀的分水嶺。全面地了解JVM的工
    的頭像 發(fā)表于 08-20 15:25 ?145次閱讀
    從原理聊<b class='flag-5'>JVM</b>(<b class='flag-5'>一</b>):染色標(biāo)記和垃圾回收算法

    weblogic jvm參數(shù)配置

    ,讓我們來了解些常用的JVM參數(shù): -Xms 和 -Xmx參數(shù):這些參數(shù)分別用于設(shè)置Java虛擬機(jī)的初始堆大小和最大堆大小。-Xms設(shè)置初始堆大小,-Xmx設(shè)置最大堆大小。通過增大-Xmx參數(shù)的值,可以增加JVM能夠使用的內(nèi)存
    的頭像 發(fā)表于 12-05 14:31 ?1259次閱讀

    jvm和jmm的區(qū)別

    程序中的內(nèi)存訪問規(guī)則。盡管 JVM 和 JMM 有許多共同點(diǎn),但它們也有些顯著的區(qū)別。本文將詳細(xì)介紹 JVM 和 JMM 的區(qū)別,幫助讀者更好地理解這兩個概念。 首先,我們來看
    的頭像 發(fā)表于 12-05 14:27 ?1233次閱讀

    jvm配置的mx

    JVM配置中的mx參數(shù)主要用于設(shè)置JVM的最大堆內(nèi)存大小。本文將詳細(xì)介紹mx參數(shù)的作用、配置方法以及如何選擇合適的值。 、mx參數(shù)的作用 在JVM中,堆內(nèi)存用于存放對象實(shí)例以及相關(guān)數(shù)
    的頭像 發(fā)表于 12-05 14:24 ?648次閱讀

    jvm調(diào)優(yōu)工具有哪些

    JVM調(diào)優(yōu)是提高Java應(yīng)用程序性能的重要手段,而JVM調(diào)優(yōu)工具則是輔助開發(fā)人員進(jìn)行調(diào)優(yōu)工作的利器。下面將介紹些常用的JVM調(diào)優(yōu)工具。 JConsole JConsole是JDK自帶
    的頭像 發(fā)表于 12-05 11:44 ?982次閱讀

    jvm參數(shù)的設(shè)置和jvm調(diào)優(yōu)

    JVM(Java虛擬機(jī))參數(shù)的設(shè)置和調(diào)優(yōu)對于提高Java應(yīng)用程序的性能和穩(wěn)定性非常重要。在本文中,我們將詳細(xì)介紹JVM參數(shù)的設(shè)置和調(diào)優(yōu)方法。 、JVM參數(shù)的設(shè)置 內(nèi)存參數(shù): -Xms
    的頭像 發(fā)表于 12-05 11:36 ?1267次閱讀

    jvm調(diào)優(yōu)參數(shù)

    JVM(Java虛擬機(jī))是Java程序的運(yùn)行環(huán)境,它負(fù)責(zé)解釋Java字節(jié)碼并執(zhí)行相應(yīng)的指令。為了提高應(yīng)用程序的性能和穩(wěn)定性,我們可以調(diào)優(yōu)JVM的參數(shù)。 JVM調(diào)優(yōu)主要涉及到堆內(nèi)存、垃圾收集器、線程棧
    的頭像 發(fā)表于 12-05 11:29 ?560次閱讀

    jvm內(nèi)存模型和內(nèi)存結(jié)構(gòu)

    JVM(Java虛擬機(jī))是Java程序的運(yùn)行平臺,它負(fù)責(zé)將Java程序轉(zhuǎn)換成機(jī)器碼并在計算機(jī)上執(zhí)行。在JVM中,內(nèi)存模型和內(nèi)存結(jié)構(gòu)是兩個重要的概念,本文將詳細(xì)介紹它們。 、JVM內(nèi)存
    的頭像 發(fā)表于 12-05 11:08 ?806次閱讀

    jvm內(nèi)存溢出該如何定位解決

    超出限制和堆空間不足。 定位JVM內(nèi)存溢出問題是個比較復(fù)雜的任務(wù),需要結(jié)合工具和技術(shù)來進(jìn)行分析和解決。本文將介紹些常用的調(diào)試和解決內(nèi)存溢出問題的工具和技術(shù)。 、理解
    的頭像 發(fā)表于 12-05 11:05 ?1226次閱讀

    jvm的dump太大了怎么分析

    分析大型JVM dump文件可能會遇到的些挑戰(zhàn)。首先,JVM dump文件通常非常大,可能幾百M(fèi)B或幾個GB。這是因為它們包含了JVM的完整內(nèi)存快照,包括堆和棧的所有對象和線程信息。
    的頭像 發(fā)表于 12-05 11:01 ?2207次閱讀

    讀懂車規(guī)級AEC-Q認(rèn)證

    讀懂車規(guī)級AEC-Q認(rèn)證
    的頭像 發(fā)表于 12-04 16:45 ?843次閱讀

    讀懂微力扭轉(zhuǎn)試驗機(jī)的優(yōu)勢

    讀懂微力扭轉(zhuǎn)試驗機(jī)的優(yōu)勢
    的頭像 發(fā)表于 11-30 09:08 ?504次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>讀懂</b>微力扭轉(zhuǎn)試驗機(jī)的優(yōu)勢

    讀懂,什么是BLE?

    讀懂,什么是BLE?
    的頭像 發(fā)表于 11-27 17:11 ?2020次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>讀懂</b>,什么是BLE?

    讀懂NTN衛(wèi)星通信

    NTN衛(wèi)星通信是什么,為何在當(dāng)下成為熱點(diǎn),它可以解決什么問題,芯訊通有推出與之對應(yīng)的產(chǎn)品嗎? 帶你讀懂 NT N! 什么是NTN衛(wèi)星通信? NTN( Non-Terrestrial
    的頭像 發(fā)表于 11-09 19:15 ?1417次閱讀