天天看點

Java性能調優面試-5深入淺出JVM調優

深入淺出JVM調優

基本概念:

JVM把記憶體區分為堆區(heap)、棧區(stack)和方法區(method)。由于本文主要講解JVM調優,是以我們可以簡單的了解為,JVM中的堆區中存放的是實際的對象,是需要被GC的。其他的都無需GC。

下圖文JVM的記憶體模型

Java性能調優面試-5深入淺出JVM調優

從圖中我們可以看到,

1、JVM實質上分為三大塊,年輕代(YoungGen),年老代(Old Memory),及持久代(Perm,在Java8中被取消,我們不做深入介紹)。

2、垃圾回收GC,分為2種,一是Minor GC,可以可以稱為YGC,即年輕代GC,當Eden區,還有一種稱為Major GC,又稱為FullGC。

3、GC原理:

我們可以看到年輕代包括Eden區(對象剛被new出來的時候,放到該區),S0和S1,是幸存者1區和幸存者2區,從名字可以看出,是當發生YGC,沒有被任何其他對象所引用的對象将會從記憶體中被清除,還被其他對象引用的則放到幸存者區。當發生多次YGC,在S0、S1區多次沒有被清楚的對象,則會被移到老年代區域。當老年代區域被占滿的時候,則會發送FullGC。

無論是YGC或是FullGC,都會導緻stop-the-world,即整個程式停止一些事務的處理,隻有GC程序允許以進行垃圾回收,是以如果垃圾回收時間較長,部分web或socket程式,當終端連接配接的時候會報connetTimeOut或readTimeOut異常,

4、從JVM調優的角度來看,我們應該盡量避免發生YGC或FullGC,或者使得YGC和FullGC的時間足夠的短。

JMV調優的準備工作。

1)、配置jstatd的遠端RMI服務(當我們要看遠端伺服器上JAVA程式的GC情況的時候,需要執行此步驟),允許JVM工具檢視JVM使用情況。

将如下的代碼存為檔案 jstatd.all.policy,放到JAVA_HOME/bin中,其内容如下:不知道JAVA_HOME目錄的,可以執行 which java檢視。

grant codebase "file:${java.home}/../lib/tools.jar" {

permission java.security.AllPermission;

};

執行指令jstatd -J-Djava.security.policy=jstatd.all.policy -J-Djava.rmi.server.hostname=10.27.20.38 &

(10.27.20.38為你伺服器的ip位址,&表示用守護線程的方式運作)

2)、執行C:\glassfish4\jdk7\bin\jvisualvm.exe 打開JVM控制台。

工具--插件--中找到Visual GC插件進行安裝.

3)、對要執行java程式進行調優,以 c1000k.jar為例,在該jar包所在目錄下建立一個start.sh檔案,檔案内容如下。

java -server -Xms4G -Xmx4G -Xmn2G -XX:SurvivorRatio=1 -XX:+UseConcMarkSweepGC -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=1100 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -jar c1000k.jar&

通過這樣的配置,使用JVM控制台即可檢視JVM(CPU/記憶體)及垃圾回收的情況。

4)、控制台配置

打開\jvisualvm.exe,遠端---添加遠端主機---輸入遠端IP----添加JMX連接配接

Java性能調優面試-5深入淺出JVM調優

5)、下面開始正式的JVM調優。

5.1 JVM調優核心為調整年輕代、年老大的記憶體空間大小及使用GC發生器的類型等。回到上文的start.sh檔案内容,我們來分下:

java -server -Xms4G -Xmx4G -Xmn2G -XX:SurvivorRatio=1 -XX:+UseConcMarkSweepGC -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=1100 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -jar c1000k.jar&

這台機器是一個4G記憶體的機器,是以:

-Xms4G 是指: JVM啟動時整個堆(包括年輕代,年老代)的初始化大小。

-Xmx4G 是指: JVM啟動時整個堆的最大值。

-Xmn2G是指:年輕代的空間大小,剩下的是年老代的空間。

-XX:SurvivorRatio=1是指:年輕代空間中2個Survivor空間與Eden空間的大小比例。此處為1:1:1,算法如下:比如整個年輕代空間為2G,如果比例為1,那麼2/3,則S0/S1/Eden的空間大小是同樣的,為666M。

該值不設定,則JDK預設為比例為8,那麼是1:1:8,通過上面的算法可以得出S0/S1的大小。我們可以看到官方通過增大Eden區的大小,來減少YGC發生的次數,但有時我們發現,雖然次數減少了,但Eden區滿

的時候,由于占用的空間較大,導緻釋放緩慢,此時stop-the-world的時間較長,是以需要按照程式情況去調優。

-XX:+UseConcMarkSweepGC是指:使用GC的回收類型。這裡是CMS類型,JDK1.7以後推薦使用+UseG1GC,被稱為G1類型(或Garbage First)的回收器。

5.2當我們設定好start.sh的參數值後,執行./start.sh此時就啟動了。

我們可以通過jvisualvm.exe中的Visual GC插件檢視GC的圖形,我們也可以再伺服器上執行:jstat -gc 15016 1000,看到每1秒鐘java程序号為15016的GC回收情況。

[[email protected] c1000k]# jstat -gc 15016 1000

S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT

699008.0 699008.0 29980.4 0.0 699136.0 116881.6 2097152.0 660769.4 21248.0 20071.0 354 54.272 0 0.000 54.272

699008.0 699008.0 29980.4 0.0 699136.0 118344.8 2097152.0 660769.4 21248.0 20071.0 354 54.272 0 0.000 54.272

699008.0 699008.0 29980.4 0.0 699136.0 119895.5 2097152.0 660769.4 21248.0 20071.0 354 54.272 0 0.000 54.272

699008.0 699008.0 29980.4 0.0 699136.0 121383.1 2097152.0 660769.4 21248.0 20071.0 354 54.272 0 0.000 54.272

解釋如下:

S0C 是指:Survivor0區的配置設定空間

S0U 是指:Survivor1區的已經使用的空間

EC是指:Eden區所使用的空間

EU是指:Eden區目前使用的空間

OC是指:老年代配置設定的空間

OU是指:老年代目前使用的空間

PC是指:持久待配置設定的空間

PU是指:持久待目前使用的空間

YGC是指:年輕代發生的次數,這裡是354次

YGCT是指:年輕代發送的總時長,這裡是54.272秒,是以每次年輕代發生GC,即平均每次stop-the-world的時長為54.272/354=0.153秒。

FGC是指:年老代回收的次數,或者成為FullGC的次數。

FGCT是指:年老代發生回收的總時長。

GCT是指:包括年輕代YGC及年老代FGC的總時間長。

通常結合圖形或資料,我們可以看到當EU即将等于EC的時候,此時發生YGC,是以YGC次數+1,YGCT時間增加。

經過實際的調優測試我們發現,當發生YGC的時候,如果S0U或S1U區如果有任意一個區域為0的時候,此時YGC的速度很快,相反如果S0U或者S1U中都有資料,或相對滿的時候,此時YGC的時間邊長,這就是因為S0/S1及Eden區的比例問題導緻的。

5.3經過一定時間的調優,我們基本上可以使得YGC的次數非常少,時間非常快,很長時間,數天都不會發生FGC,此時JVM的調優算是一個好的結果。

5.4 在MAC電腦上可以通過jconsole調出圖形化分析工具。