日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JVM原理探究及调优方法论

發(fā)布時間:2023/12/19 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JVM原理探究及调优方法论 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1 此文目的

本文不準(zhǔn)備從盤古開天地開始講述JVM的種種,相關(guān)的文章網(wǎng)上太多了,大多也無非轉(zhuǎn)來轉(zhuǎn)去,連圖都差不多。筆者只整理個提綱挈領(lǐng)的學(xué)習(xí)路線指南,并對自己學(xué)習(xí)過程中遇到的坑和容易混淆和忽視的地方作個總結(jié)。

2 JVM內(nèi)存模型

2.1 內(nèi)存模型

內(nèi)存區(qū)域劃分有多個維度,相同區(qū)域在不同維度的名稱并不一樣。如下圖所示

可以看到,survivor區(qū)被劃分為了survivor0和survivor1兩個區(qū)域,但是在講MinorGC的原理時,我們又會說survvior to和survivor from兩個區(qū)域。事實(shí)上,survivor0和survivor1是物理維度的劃分,而survivor to和survivor from是邏輯維度的劃分,在MinorGC的過程中,survivor0和survivor1交替擔(dān)當(dāng)to區(qū)和from區(qū)。 來仔細(xì)解釋一下MinorGC的過程: 在GC開始的時候,對象只會存在于Eden區(qū)和名為“From”的Survivor區(qū),Survivor區(qū)“To”是空的。緊接著進(jìn)行GC,Eden區(qū)中所有存活的對象都會被復(fù)制到“To”,而在“From”區(qū)中,仍存活的對象會根據(jù)他們的年齡值來決定去向。年齡達(dá)到一定值(年齡閾值,可以通過-XX:MaxTenuringThreshold來設(shè)置)的對象會被移動到年老代中,沒有達(dá)到閾值的對象會被復(fù)制到“To”區(qū)域。經(jīng)過這次GC后,Eden區(qū)和From區(qū)已經(jīng)被清空。這個時候,“From”和“To”會交換他們的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎樣,都會保證名為To的Survivor區(qū)域是空的。Minor GC會一直重復(fù)這樣的過程,直到“To”區(qū)被填滿,“To”區(qū)被填滿之后,會將所有對象移動到年老代中。大致如下圖所示:

2.2 方法區(qū)和永久代

這兩個概念,很多時候都被當(dāng)做是同一個概念。實(shí)際上,“方法區(qū)”是java虛擬機(jī)規(guī)范中對存放類信息,字段,方法,常量,靜態(tài)變量,接口和常量池的內(nèi)存區(qū)域的定義,而“永久代”則是HotSpot VM在1.8版本以前對于方法區(qū)的具體實(shí)現(xiàn)。由于java虛擬機(jī)規(guī)范并沒有對方法區(qū)的具體實(shí)現(xiàn)作限制,所以HotSpot VM和JRocket VM對于方法區(qū)的實(shí)現(xiàn)都是不一樣的,JRocket中就沒有永久代的概念。而在1.8及1.8以后的版本中,HotSpot VM用"元空間"--metaspace來代替永久代,實(shí)現(xiàn)方法區(qū)。 這個變化帶來的就是VM參數(shù)的變化,所有的PermGen都被替換成了MetaSpace。并且metaSpace不再使用堆內(nèi)存,而是使用系統(tǒng)內(nèi)存。但是該發(fā)生的OOM一樣會發(fā)生。原因也基本都是加載到內(nèi)存中的 class 數(shù)量太多或者體積太大。

3.GC

3.1 GC算法

GC算法和GC收集器也是兩個維度的概念。 GC算法包括清除算法(也叫標(biāo)記清除算法),復(fù)制算法,標(biāo)記-整理算法。 不同垃圾收集器針對不同的內(nèi)存區(qū)域,采用不同的GC算法。 具體介紹,網(wǎng)上相關(guān)資料很多,可以參考這篇文章:blog.csdn.net/xiaoping091…

3.2 垃圾收集器

垃圾收集器經(jīng)歷了從串行收集器到并行收集器,再到并發(fā)收集器的進(jìn)化過程。這三者的區(qū)別如下圖所示

串行和并行的區(qū)別比較容易理解,而CMS垃圾收集器的原理要注意的是,雖然它是并發(fā)收集器,但它的GC線程并不是完完全全地與應(yīng)用的進(jìn)程并發(fā)進(jìn)行,它只是通過用兩次短暫停來代替并行GC的一次長暫停,以期達(dá)到減少應(yīng)用線程暫停的目的,詳見CMS垃圾回收機(jī)制

不同版本默認(rèn)使用的垃圾收集器以及支持開發(fā)者定制的垃圾收集器都是不一樣的 jdk1.7 默認(rèn)垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代) jdk1.8 默認(rèn)垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代) jdk1.9 默認(rèn)垃圾收集器G1 與此同時,通過設(shè)置JVM參數(shù)也可以自己選擇垃圾收集器。如要開啟G1垃圾回收器,可以用-XX:+UseG1GC,支持G1垃圾回收器的JDK最低版本為JDK 7u4。在用戶自己選擇垃圾收集器的時候,要注意JDK版本的問題。 筆者用表格的形式列出了新生代和老年代的GC收集器的常見搭配方案:

3.3 Full GC觸發(fā)條件

頻繁FullGC導(dǎo)致的stop the world的現(xiàn)象,會大大影響系統(tǒng)的穩(wěn)定性。盡管一代又一代的垃圾收集器的優(yōu)化,使得stop the world的時間越來越短,但是在大型應(yīng)用中,還是避之不及。 出發(fā)FullGC的情況有以下幾種:

  • System.gc()方法的調(diào)用
  • 老年代不足
  • 方法區(qū)不足
  • concurrent mode failure concurrent mode failure是在執(zhí)行CMS GC的過程中同時有對象要放入老年代,而此時老年代空間不足造成的(有時候“空間 不足”是CMS GC時當(dāng)前的浮動垃圾過多導(dǎo)致暫時性的空間不足觸發(fā)Full GC)。
  • promotion failed minor gc時年輕代的存活區(qū)空間不足而晉升老年代,老年代又空間不足而觸發(fā)full gc
  • 統(tǒng)計得到的Minor GC晉升到舊生代的平均大小大于老年代的剩余空間 當(dāng)準(zhǔn)備要觸發(fā)一次young GC時,如果發(fā)現(xiàn)統(tǒng)計數(shù)據(jù)說之前young GC的平均晉升大小比目前old gen剩余的空間大,則不會觸發(fā)young GC而是轉(zhuǎn)為觸發(fā)full GC(因?yàn)镠otSpot VM的GC里,除了CMS的concurrent collection之外,其它能收集old gen的GC都會同時收集整個GC堆,包括young gen,所以不需要事先觸發(fā)一次單獨(dú)的young GC)。
  • 3.3.1 OOM的類型

    通常情況下,JVM的GC機(jī)制能保證應(yīng)用的正常運(yùn)行,導(dǎo)致系統(tǒng)頻繁FullGC的原因百分之九十都是內(nèi)存溢出(OOM)。OOM分為以下幾類:

  • Java.lang.OutOfMemeoryError:Java heap space 堆空間的內(nèi)存溢出,可能的原因是某個可達(dá)性分析認(rèn)為不能被回收的對象隨著時間推移變得越來越大,例如某個static類型的map對象,被不停地塞入鍵值對,也可能是大循環(huán)或者死循環(huán)不斷創(chuàng)建對象,而對象分配內(nèi)存的速度超過了GC清理內(nèi)存的速度。
  • Java.lang.OutOfMemeoryError:GC overhead limit exceeded 這種OOM異常是Hotspot VM 1.6定義的一個策略,通過統(tǒng)計GC時間來預(yù)測是否要OOM了,提前拋出異常,防止OOM發(fā)生。Sun 官方對此的定義是:“并行/并發(fā)回收器在GC回收時間過長時會拋出OutOfMemroyError。過長的定義是,超過98%的時間用來做GC并且回收了不到2%的堆內(nèi)存。用來避免內(nèi)存過小造成應(yīng)用不能正常工作?!?那么為什么會出現(xiàn)這種GC效率低下的現(xiàn)象呢?通常是因?yàn)槔夏甏鷥?nèi)存占有過多導(dǎo)致的頻繁GC,這種情況下,可以增加-verbose:gc -XX:+PrintGCDetails來分析具體原因,也可以加-XX:+HeapDumpOnOutOfMemoryError,這樣OOM時會自動做Heap Dump,第二種方法適用于所有OOM異常的排查。
  • Java.lang.OutOfMemoryError: PermGen space(JAVA8引入了Metaspace區(qū)域)方法區(qū)內(nèi)存溢出,通常是因?yàn)榧虞d的類過多,可以先排除程序問題導(dǎo)致的重復(fù)類加載,或者加大方法區(qū)內(nèi)存的分配
  • Java.lang.OutOfMemoryError: unable to create new native thread 產(chǎn)生這種異常的原因是由于系統(tǒng)在不停地創(chuàng)建大量的線程,且不進(jìn)行釋放。
  • 4. JVM調(diào)優(yōu)

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

    正確設(shè)置JVM參數(shù),可以盡可能多地避免系統(tǒng)資源浪費(fèi),盡可能詳細(xì)地掌握系統(tǒng)運(yùn)行情況,并且對可能出現(xiàn)的問題防患于未然。

    Xms:堆初始空間

    Xmx:堆最大空間

    Xmn:年輕代大小

    XX:MaxNewSize 新生代最大空間 建議設(shè)置為整個堆的1/3到1/4

    XX:NewSize

    XX:MaxTenuringThreshold survivor中到老年代中的年齡閾值

    Xss:每個線程的棧大小

    java -XX:+PrintCommandLineFlags -version 得到JDK建議的內(nèi)存分配大小

    tomcat設(shè)置catalina.sh:

    export JAVA_OPTS="-server –Xms1024m -Xmx1024m -XX:+UseParallelOldGC -verbose:gc -Xloggc:../logs/gc.log

    -XX:+PrintGCDetails -XX:+PrintGCTimeStamps"

    -XX:+PrintCommandLineFlagsjvm參數(shù)可查看默認(rèn)設(shè)置收集器類型

    -XX:+PrintGCDetails亦可通過打印的GC日志的新生代、老年代名稱判斷

    4.2 JVM監(jiān)控

    • 1.本機(jī)環(huán)境下,推薦一款idea上的插件VisualVM Launcher,實(shí)際就是聯(lián)動了JDK開發(fā)包中自帶的jvisualvm.exe監(jiān)控軟件。也可以設(shè)置遠(yuǎn)程監(jiān)控。具體使用方法,可以參考這篇文章https://blog.csdn.net/wngpenghao/article/details/82884874IDEA Java性能分析插件VisualVM Launcher 配置(JAVA VisualVM 與Jconsole配置相同)

    • 2.Linux的相關(guān)命令: jstat命令可以對jvm從各維度進(jìn)行統(tǒng)計,詳細(xì)使用參考jstat命令查看jvm的GC情況

    • 3.VM參數(shù)設(shè)置時,指定打印出gc日志 -Xloggc:../logs/gc.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps 詳細(xì)的參數(shù)設(shè)置以及gc日志該如何閱讀,可以參考java之GC日志該怎么看

    4.3 JVM異常排查

  • 保存dump 當(dāng)使用監(jiān)控軟件或者命令查看發(fā)現(xiàn)JVM異常時,應(yīng)第一時間保存下dump現(xiàn)場。 命令是jmap -dump:format=b,file=文件名[pid] pid是服務(wù)進(jìn)程
  • 如果是使用jvisualvm就更方便了,直接點(diǎn)擊如圖所示的按鈕即可:

    2. 分析dump eclipse有一款插件叫做Memory Analyzer(MAT),但是目前idea并沒有這款插件 此外,jhat是sun 1.6及以上版本中自帶的一個用于分析JVM 堆DUMP 文件的工具,基于此工具可分析JVM HEAP 中對象的內(nèi)存占用情況 jhat -J-Xmx1024M [file] 執(zhí)行后等待console 中輸入start HTTP server on port 7000 即可使用瀏覽器訪問 IP:7000 可以特別關(guān)心下圖標(biāo)出的這個選項(xiàng) 這對于排查堆內(nèi)存溢出非常有效

    4.4 實(shí)戰(zhàn)例子

    由于實(shí)際工作中,能接觸到JVM機(jī)會的機(jī)會并不多,所以筆者整理了一些經(jīng)典實(shí)例

    Metaspace溢出排查過程

    分享一次 Java 內(nèi)存泄漏的排查

    一次生產(chǎn)的 JVM 優(yōu)化案例

    JVM成長之路,記錄一次內(nèi)存溢出導(dǎo)致頻繁FGC的問題排查及解決

    非常詳細(xì)的jvm調(diào)優(yōu)實(shí)例,性能瓶頸定位

    轉(zhuǎn)載于:https://juejin.im/post/5cf500c7f265da1b855c40c3

    總結(jié)

    以上是生活随笔為你收集整理的JVM原理探究及调优方法论的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。