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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JVM原理探究及调优方法论

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

1 此文目的

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

2 JVM內存模型

2.1 內存模型

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

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

2.2 方法區和永久代

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

3.GC

3.1 GC算法

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

3.2 垃圾收集器

垃圾收集器經歷了從串行收集器到并行收集器,再到并發收集器的進化過程。這三者的區別如下圖所示

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

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

3.3 Full GC觸發條件

頻繁FullGC導致的stop the world的現象,會大大影響系統的穩定性。盡管一代又一代的垃圾收集器的優化,使得stop the world的時間越來越短,但是在大型應用中,還是避之不及。 出發FullGC的情況有以下幾種:

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

    通常情況下,JVM的GC機制能保證應用的正常運行,導致系統頻繁FullGC的原因百分之九十都是內存溢出(OOM)。OOM分為以下幾類:

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

    4.1 調優參數

    正確設置JVM參數,可以盡可能多地避免系統資源浪費,盡可能詳細地掌握系統運行情況,并且對可能出現的問題防患于未然。

    Xms:堆初始空間

    Xmx:堆最大空間

    Xmn:年輕代大小

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

    XX:NewSize

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

    Xss:每個線程的棧大小

    java -XX:+PrintCommandLineFlags -version 得到JDK建議的內存分配大小

    tomcat設置catalina.sh:

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

    -XX:+PrintGCDetails -XX:+PrintGCTimeStamps"

    -XX:+PrintCommandLineFlagsjvm參數可查看默認設置收集器類型

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

    4.2 JVM監控

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

    • 2.Linux的相關命令: jstat命令可以對jvm從各維度進行統計,詳細使用參考jstat命令查看jvm的GC情況

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

    4.3 JVM異常排查

  • 保存dump 當使用監控軟件或者命令查看發現JVM異常時,應第一時間保存下dump現場。 命令是jmap -dump:format=b,file=文件名[pid] pid是服務進程
  • 如果是使用jvisualvm就更方便了,直接點擊如圖所示的按鈕即可:

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

    4.4 實戰例子

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

    Metaspace溢出排查過程

    分享一次 Java 內存泄漏的排查

    一次生產的 JVM 優化案例

    JVM成長之路,記錄一次內存溢出導致頻繁FGC的問題排查及解決

    非常詳細的jvm調優實例,性能瓶頸定位

    轉載于:https://juejin.im/post/5cf500c7f265da1b855c40c3

    總結

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

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。