1. 程式人生 > >四:JVM調優與常見異常處理方案

四:JVM調優與常見異常處理方案

在jvm調優之前,我們必須先了解jvm的記憶體模型與GC回收機制,這些在我前面的文章裡面有介紹!接下來我們通過一個案例來調整jvm效能。

一:調優案例:

  1.1 編寫demo

import java.text.DecimalFormat;
/**
    -XX:+PrintGC         GC回收的時候列印相關日誌
    -XX:+UseSerialGC     序列回收
    -XX:+PrintGCDetails  顯示詳細的GC日誌
    
    -Xms               堆初始值
    -Xmx               堆最大可用值
    -XX:SurvivorRatio  新生代中eden空間和from(s0),to(s1)空間的比例.
    
    -XX:NewRation=   新生帶與老年代的比例
    -Xss  棧的大小(棧的深度)
 
*/ public class JVMDemo { public static void main(String[] args) throws InterruptedException { // 最大記憶體 long maxMemory = Runtime.getRuntime().maxMemory(); System.out.println("最大堆記憶體為: "+format(maxMemory)+"MB"); // 已經使用記憶體 long totalMemory = Runtime.getRuntime().totalMemory(); System.out.println(
"已使用堆記憶體: "+format(totalMemory)+"MB"); // 當前剩餘記憶體 long freeMemory = Runtime.getRuntime().freeMemory(); System.out.println("剩餘堆記憶體為: "+format(freeMemory)+"MB"); byte[] b1 = new byte[4 * 1024 * 1024]; System.out.println("-----分配了4m堆記憶體-----");
// 當前剩餘記憶體 long freeMemory2 = Runtime.getRuntime().freeMemory(); System.out.println("剩餘堆記憶體為: "+format(freeMemory2)+"MB"); } /** * 將堆記憶體單位格式化成 MB */ static private String format(long maxMemory) { float num = (float) maxMemory / (1024 * 1024); DecimalFormat df = new DecimalFormat("0.00");// 格式化小數 String s = df.format(num);// 返回的是String型別 return s; } }

   1.2 配置引數,列印jvm資訊:  右鍵 --> Run As --> Run Configurations... --> Arguments --> VM arguments 輸入配置資訊  -XX:+PrintGCDetails -XX:+UseSerialGC

  

  1.3 執行java程式碼, 檢視jvm資訊

// 這些資訊與電腦配置引數有關,我們的具體資料可能不一樣,但是記憶體模型資料比例是一樣的
最大堆記憶體為: 1890.81MB  // 大約1900MB
已使用堆記憶體: 119.88MB   // 已用120MB
剩餘堆記憶體為: 117.89MB   // 剩餘117MB
-----分配了4m堆記憶體-----
剩餘堆記憶體為: 113.89MB   // 用了4mb後還剩113MB
Heap
 def new generation   total 38080K, used 6805K [0x0000000085c00000, 0x0000000088550000, 0x00000000ae800000)
 // 可以看出新生代中預設 eden區 from區 to區比例為 33856:4224:4224 即 8:1:1
  eden space 33856K,  20% used [0x0000000085c00000, 0x00000000862a57a8, 0x0000000087d10000)
  from space 4224K,   0% used [0x0000000087d10000, 0x0000000087d10000, 0x0000000088130000)
  to   space 4224K,   0% used [0x0000000088130000, 0x0000000088130000, 0x0000000088550000)
 // 老年代和新生代預設比例為 84672:(33856+4224+4224)  即2:1
 tenured generation   total 84672K, used 0K [0x00000000ae800000, 0x00000000b3ab0000, 0x0000000100000000)
   the space 84672K,   0% used [0x00000000ae800000, 0x00000000ae800000, 0x00000000ae800200, 0x00000000b3ab0000)
 // 元空間
 Metaspace       used 3652K, capacity 4600K, committed 4864K, reserved 1056768K
  class space    used 410K, capacity 428K, committed 512K, reserved 1048576K

   1.4 jvm常見引數含義

  1.5 調優總結:

    1.將初始的堆大小與最大堆大小相等,來垃圾回收次數從而提高效率。
    2.將新生代或老年代的比例設定為1/3 或者 1/4,讓GC儘量去新生代去回收。
         -Xms2000m -Xmx2000m -XX:+PrintGCDetails -XX:+UseSerialGC -XX:NewRatio=4

    此時重新執行java類, 可以對比jvm資訊

     

  1.6 Tomcat修改JVM引數:  linux系統修改tomcat/bin/catalina.sh檔案,win系統修改tomcat/bin/catalina.bat檔案。

    JAVA_OPTS="-server -Xms800m -Xmx800m -XX:PermSize=256m -XX:MaxPermSize=512m -XX:MaxNewSize=512m"

 

====================================================================

 

什麼是記憶體洩漏及如何避免

     記憶體洩漏即:物件可達但不可用,一個物件不再需要使用本該回收時,另一個正在使用的物件卻持有它的引用,導致無法回收停留在堆內中。

     防止記憶體洩露:

      1.儘早釋放無用物件的引用, 將不需要使用的物件設定為null,暗示垃圾收集器來收集該物件,防止發生記憶體洩漏。  

      2.程式進行字串處理時,儘量避免使用String,而應該使用StringBuffer。

         3.儘量少用靜態變數

      4.儘量運用物件池技術以提高系統性能

Jvm常見異常處理方案

   記憶體洩漏: java.lang.OutOfMemory Error:Java heap space

       解決思路:  1. 先檢視是不是記憶體洩漏,如果是通過GC Root的路徑來排查

            2. 檢視堆記憶體是否有物件沒釋放。

            3. 加大實體記憶體 –Xms, -Xmx,最好-Xms = -Xmx,減少記憶體擴充套件的開銷。

                 控制引數:  -Xms (starting 堆的起始大小)         -Xmx (max 堆的最大大小)         -Xmn (new 堆的新生代大小)

  記憶體溢位: java.OutOfMemory Error:PermGen space

                  解決思路:  增加引數:-XX:PrintGCDetails,-XX:+PrintGCTimeStamps和-XX:+PrintGCDateStamps 

  執行緒請求的棧深度大於虛擬機器所允許的最大深度java.lang.StackOverflow Error

      解決思路: 可以將棧的深度,理解為陣列的長度。

      控制引數:  1. 加大-Xss(每個執行緒的堆疊大小)引數。  

           2. 更換64位虛擬機器。

           3. 減少執行緒。        

           4. 減少最大堆(Xmx)。

         java.lang.OutOfMemory Error,有allocate、Native字樣

     解決思路:  加大本地記憶體-MaxDirectMemorySize如不指定則與-Xmx一致。

    以centos6.8 ,100G的記憶體,參考配置如下:

      JAVA_OPTS="-Xms8g -Xmx8g

            -XX:ParallelGCThreads=8

            -XX:PermSize=2g

            -XX:MaxPermSize=4g

            -Xss512k -Xmn6g

            -XX:-DisableExplicitGC

            -XX:+UseCompressedOops

            -XX:+UseConcMarkSweepGC

            -XX:+CMSParallelRemarkEnabled"

   CATALINA_OPTS="-Xms8g -Xmx8g

            -XX:ParallelGCThreads=8

            -XX:PermSize=2g

            -XX:MaxPermSize=4g

            -Xss512k -Xmn6g

            -XX:-DisableExplicitGC

            -XX:+UseCompressedOops

            -XX:+UseConcMarkSweepGC

            -XX:+CMSParallelRemarkEnabled"