Java虛擬機內存模型及垃圾回收監控調優

Java虛擬機內存模型及垃圾回收監控調優html

     若是你想理解Java垃圾回收若是工做,那麼理解JVM的內存模型就顯的很是重要。今天咱們就來看看JVM內存的各不一樣部分及若是監控和實現垃圾回收調優。java

JVM內存模型        算法

 

   正如你上圖所看到的,JVM內存能夠劃分爲不一樣的部分,廣義上,JVM堆內存能夠劃分爲兩部分:年輕代和老年代(Young Generation and Old Generation)編程

年輕代(Young Generation)服務器

年輕代用於存放由new所生成的對象。當年輕代空間滿時,垃圾回收就會執行。這個垃圾回收咱們稱之爲 最小化垃圾回收(Minor GC)。年輕代又能夠分爲三分部: 一個Eden內存區(Eden Memory)和兩個Survivor 內存區(Survivor Memory)多線程

 

關於年輕代的重點:併發

  • 大多數新建立的對象都存放在Eden內存區。
  • Eden區存滿對象時,最小化GC將會被執行,全部存活的對象被移到其中一個Survivor區。
  • 最小化GC同時也會檢查存活的對象並將它們移到另外一個Survivor區,因此在一段時間,其中一個Survivor區老是空的。
  • 存活的對象通過屢次GC後,將會被移到老年代(Old Generation)一般年輕代轉化多長時間變爲老年代都會設置一個閥值。

老年代(Old Generation)oracle

   老年代內存包含那些通過屢次最小化GC且存活的對象。 一般當老年代內存滿時垃圾回收會被執行。咱們稱之爲大GC (Major GC),一般這個過程會花費很長的時間。jvm

Stop the World Eventjsp

全部的垃圾回收都是「阻塞」事件(「Stop the World」 events) ,由於全部應用程序線程必須中止,直到垃圾回收操做完成以後才能繼續。

因爲年輕代老是保存着短時間存活的對象,最小化GC很是快,應用程序也不會受到影響。然而大GC(Major GC)因爲它要檢查全部存活的對象,因此須要花費很長的時間。 大GC會在垃圾回收期間使得你的應用程序沒有任何響應,應最大化的減小此類GC。若是你有一個即時響應應用程序且老是有不少的大GC在執行。你會發現存在超時錯誤。

垃圾回器掃行的時間依賴於GC所使用的策略。這就是爲何對於那些高響應用程序來講,GC的監控與調優顯得很是必要。

永久代(Permanent Generation)

永久代或持久代包含JVM用來描述應用程序中使用的類和方法的元數據。注意 永久代不是JAVA堆內存的一部分。

JVM在運行期間依據應用程序所使用的類來存入永久代,同時也包含Java SE庫類各方法。 永久代中的對象經過全GC(Full GC)來進行垃圾回收。

方法區Method Area

方法區是永久代的一部分,用於存儲類結構(運行時的常量和靜態變量)及方法和構造的代碼。

運行時常量池Runtime Constant Pool

運行時常量池是類中常量池在編譯期的表示,它包含類的運行時常量,靜態方法,它是方法區的一部分。

Java棧內存Java Stack Memory

Java 棧內存用於執行線程。包含方法短時間存活的特定值及方法中所涉及的指向堆中其它對象的引用。

Java 堆內存Switches(Java Heap Memory Switches)

 提供了大量的內存Switch,咱們能夠用來設置內存大小及它們的比率。一此經常使用的內存Switches以下。

 

VM Switch VM Switch 描述
-Xms 設置JVM啓動時初始值。
-Xmx 設置堆的最大值
-Xmn 設置年輕代的大小
-XX:PermGen 設置永久代內存的初始值
-XX:MaxPermGen 設置永久代內存的最大值
-XX:SurvivorRatio 用於提供Eden區和Survivor區的比例, 例如,若是年輕代的大小爲 10M,VM switch is -XX:SurvivorRatio=2 那麼 5 M 分配給 Eden 區,每個Survivor 區爲 2.5 M .默認比例大小爲  8。
-XX:NewRatio 老年代/新生代的比例. 默認值是 2.

 

  大多數狀況下,上述選項是很是有用的。若是你也想試試其它參數能夠查看 JVM 官方主頁

 JAVA GC

  Java GC是從內存中標記、移除非可用對象並釋放所分配的空間用於後續建立對像的過程。Java編程語言最大的功能之一就是自動垃圾回收。不像其它相似C的編程語言,它們的內存分配與回收能夠人爲操做。

  GC是後臺執行用於檢查內存中的全部對象並找出未被任務程序所引用的對象。全部這些未引用的對象將被刪除,同時空間也會被回收用於分配給其它對象。

 關於標記、刪除方法有兩個問題:

1.因爲新建立的對象將會變成不可用,全部效率上不是很高。

2.屢次GC後可用的對象很能在後續的GC後仍然可用。

 上述方法的不足在於Java的GC是分代的,在堆內存中分年輕代和老年代。 前面我已經解釋過基於最小化GC(Minor GC)和大GC(Major GC)對象是若是被掃描並從一個分代區移到別一個分區。

Java GC的類型

在應用程序中咱們可使用以下五種類型的GC。咱們可使用JVM相關設置爲應用程序開啓GC策略,如今咱們就來具體的看看.

  1. 串行GC (Serial GC -XX:+UseSerialGC): 串行GC爲年輕代和老年代GC提供簡單的標記-清除-壓縮方法。串行GC在獨立應用程序運行的少許CPU的客戶機器上很是有效。對於那些低內存佔用的應用程序很是有利。
  2. 並行GC (Parallel GC -XX:+UseParallelGC): 並行GC中大部分實現與串行GC相同,除了年輕代的垃圾回收使用N個線程,N是系統CPU內核的數量。咱們能夠經過 JVM 的 -XX:ParallelGCThreads=n 選項來控制線程的數量。並行的垃圾回收器由於使用多CPU來加速GC的實現因此也稱爲並行收集器(throughput collector).並行GC使用單線程來處理老年代的垃圾回收.
  3. 並行Old GC (Parallel Old GC  -XX:+UseParallelOldGC):此類型的GC中年輕代和老年代GC都使用多線程進行。其它與並行GC相同,
  4. 併發標記清除收集器(Concurrent Mark Sweep (CMS) Collector) (-XX:+UseConcMarkSweepGC): CMS收集器是併發短暫停收集器。它爲老年代進行垃圾回收。CMS收集器 經過與應用程序線程併發執行垃圾回收 從而縮短因GC而出現的暫停時間。CMS收集器在年輕代使用與並行收集器相同的算法。這類垃圾收集器適合不能容忍長時間暫停的響應程序。咱們能夠經過JVM中的 -XX:ParallelCMSThreads=n 來設置CMS收集器中的線程數。
  5. G1 垃圾收集器G1 Garbage Collector (-XX:+UseG1GC) Java 7中可使用G1 垃圾收集器。它的最終目標是替換掉CMS收集器。G1收集器是一個並行、併發、增量壓縮、低暫停的垃圾收集器。

      G1垃圾收集器不一樣於其它收集器,它沒有年輕代、老年代空間,它將堆空間劃分紅多個相同大小的堆區域(heap regions),當調用一次垃圾回收,它首先收集實時性不是很高的區域的數據,所以稱爲」Garbage First」。有關詳細的可參考個人另一篇Blog:Java垃圾收集器之--Garbage-First Collector 

JAVA 垃圾收集監控

   咱們可使用Java命令行和UI工具來監控應用程序的垃圾收集活動。下面的例子中,我使用Java SE Downloads 中一個演示程序。

   若是你想使用一樣的程序,前往 Java SE Downloads  頁面下載JDK 7 and JavaFX Demos and Samples 我使用的和序示例是Java2Demo.jar  能夠在jdk1.7.0_55/demo/jfc/Java2D 目錄中找到。固然了這步可選。你能夠選用任何Java程序執行GC監控命令。

  我使用的啓動演示程序的命令是:

1
pankaj@Pankaj:~ /Downloads/jdk1 .7.0_55 /demo/jfc/Java2D $ java -Xmx120m -Xms30m -Xmn10m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseSerialGC -jar Java2Demo.jar

JSTAT

    咱們可使用 jstat 命令行工具來監控JVM內存和GC活動。標準的JDK中含有此命令。所以能夠直接使用。

    運行 jstat 以前你須要知道程序的進程ID號。你能夠運行 ps -eaf | grep java 命令來獲取。

1
2
3
pankaj@Pankaj:~$ ps -eaf | grep Java2Demo.jar
501 9582  11579   0  9:48PM ttys000    0:21.66 /usr/bin/java -Xmx120m -Xms30m -Xmn10m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseG1GC -jar Java2Demo.jar
501 14073 14045   0  9:48PM ttys002    0:00.00 grep Java2Demo.jar

  個人Java程序的進程ID號爲 9582.如今咱們能夠以下執行jstat 命令。


1 pankaj@Pankaj:~$ jstat -gc 9582 1000
2  S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT
3 1024.0 1024.0  0.0    0.0    8192.0   7933.3   42108.0    23401.3   20480.0 19990.9    157    0.274  40      1.381    1.654
4 1024.0 1024.0  0.0    0.0    8192.0   8026.5   42108.0    23401.3   20480.0 19990.9    157    0.274  40      1.381    1.654
5 1024.0 1024.0  0.0    0.0    8192.0   8030.0   42108.0    23401.3   20480.0 19990.9    157    0.274  40      1.381    1.654
6 1024.0 1024.0  0.0    0.0    8192.0   8122.2   42108.0    23401.3   20480.0 19990.9    157    0.274  40      1.381    1.654
7 1024.0 1024.0  0.0    0.0    8192.0   8171.2   42108.0    23401.3   20480.0 19990.9    157    0.274  40      1.381    1.654
8 1024.0 1024.0  48.7   0.0    8192.0   106.7    42108.0    23401.3   20480.0 19990.9    158    0.275  40      1.381    1.656
9 1024.0 1024.0  48.7   0.0    8192.0   145.8    42108.0    23401.3   20480.0 19990.9    158    0.275  40      1.381    1.656

 

      

jstat命令的最後一個參數是每次輸出的時間間隔,所以它會每隔一秒打印內存及垃圾回收數據。下面詳細看看每列。

    • S0C and S1C: 這列顯示當前 Survivor0 and Survivor1 區域的大小(KB)
    • S0U and S1U: 這列顯示 Survivor0 and Survivor1 區域的使用狀況(KB). 其中一個Survivor區域老是空的
    • EC and EU: 這列顯示Eden區的當前大小及使用狀況(KB). 注意 EU 的大小逐漸增長,當達到EC大小, 最小化 GC 被調用 ,EU 的大小減少。
    • OC and OU: 這列顯示了老年代的當前大小及使用狀況(KB)
    • PC and PU: 這列顯示了 持久化代(Perm Gen) 的當前大小及使用狀況(KB)
    • YGC and YGCT: YGC 列顯示年輕代發生GC事件的數量。 YGCT 列顯示年輕代發生GC操做累計時間.  注意這兩列值都在增長與EU值減小是在同一行。這主要是最小化GC的緣由。
    • FGC and FGCT: FGC 列顯示了FUll GC發生的數量. FGCT 列顯示了FULL GC操做的累計時間. 注意Full GC 所用的時間相比年輕代GC所用的時間要大的多
    • GCT:  這列顯示了GC 操做總累計時間。 注意它是 YGCT 和 FGCT 值的總和

  jstat的優勢在於它能夠在無GUI的遠程服務器上執行。注意S0C, S1C 和EC之和爲 10M ,與咱們經過JVM選項 -Xmn10m 設置的值同樣

Java VisualVM with Visual GC

    若是你想在GUI下查看內存及GC操做。 那麼你可使用 jvisualvm 工具。Java VisualVM 也一樣包含在JDK中,你不須要單獨下載。

    只須要運行在終端上執行jvisualvm 命令來啓動Java VisualVM程序。一旦啓動,你須要經過Tools--》Plugins選項安裝Visual GC 插件,正以下圖所示。

       

   Visual GC 安裝完畢後,左邊列中打開程序前往Visual GC 部分。你將會獲得以下圖所示的JVM內存及GC截圖。

   Java GC 調優是提升應用程序吞吐量的最後選擇,只有當你發現長時間的GC致使性能降低而產生應用程序超時。

    你會在日誌中看到java.lang.OutOfMemoryError: PermGen space的錯誤信息。而後能夠嘗試監控並經過使用JVM 選項  -XX:PermGen and -XX:MaxPermGen  來增長Perm Gen內存空間。你或許也能夠嘗試使用-XX:+CMSClassUnloadingEnabled 來檢查使用CMS垃圾收集的性能如何?

   若是你發現大量的FUll GC操做,你能夠試着增長老年代內存空間。

   總之GC調優須要花費大量的精力和時間,這裏絕沒有什麼硬性或者快速的規則。你須要嘗試不一樣的選項,比較他們,並找對你應用程序來講最好的那個。

   這就是全部有關Java內存模型和垃圾回收。我但願這有助於你理解JVM內存模型及垃圾回收的過程。謝謝。

 

原文連接: JournalDev 翻譯: TonySpark
譯文連接: http://www.cnblogs.com/tonyspark/p/3731696.html

轉載請保留原文出處、譯者和譯文連接。]

相關文章
相關標籤/搜索