JVM性能優化--JVM參數配置,使用JMeter簡單測試配合說明參數調優

1、JVM參數配置

一、常見參數配置

  • -XX:+PrintGC 每次觸發GC的時候打印相關日誌
  • -XX:+UseSerialGC 串行回收
  • -XX:+PrintGCDetails 更詳細的GC日誌
  • -Xms 堆初始值
  • -Xmx 堆最大可用值
  • -Xmn 新生代堆最大可用值
  • -XX:SurvivorRatio 用來設置新生代中eden空間和from/to空間的比例.
  • -XX:NewRatio 配置新生代與老年代佔比 1:2
  • 含以-XX:SurvivorRatio=eden/from=den/to

總結:在實際工做中,咱們能夠直接將初始的堆大小與最大堆大小相等,這樣的好處是能夠減小程序運行時垃圾回收次數,從而提升效率。java

-XX:SurvivorRatio 用來設置新生代中eden空間和from/to空間的比例.算法

二、堆內存大小配置

使用示例: -Xmx20m -Xms5m
說明: 當下Java應用最大可用內存爲20M, 初始內存爲5M數組

byte[] b = new byte[4 * 1024 * 1024];
System.out.println("分配了4M空間給數組");
System.out.print("最大內存");
System.out.println(Runtime.getRuntime().maxMemory() / 1024.0 / 1024 + "M");
System.out.print("可用內存");
System.out.println(Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M");
System.out.print("已經使用內存");
System.out.println(Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");複製代碼

三、設置新生代比例參數

使用示例:-Xms20m -Xmx20m -Xmn1m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC瀏覽器

說明:堆內存初始化值20m,堆內存最大值20m,新生代最大值可用1m,eden空間和from/to空間的比例爲2/1服務器

byte[] b = null;
for (int i = 0; i < 10; i++) {
b = new byte[1 * 1024 * 1024];
}複製代碼

四、設置新生代與老年代比例參數

使用示例: -Xms20m -Xmx20m -XX:SurvivorRatio=2 -XX:+PrintGCDetails -XX:+UseSerialGC-XX:NewRatio=2多線程

說明:堆內存初始化值20m,堆內存最大值20m,新生代最大值可用1m,eden空間和from/to空間的比例爲2/1新生代和老年代的佔比爲1/2併發

2、實戰OutOfMemoryError異常

一、Java堆溢出

錯誤緣由: java.lang.OutOfMemoryError: Java heap space 堆內存溢出工具

解決辦法:設置堆內存大小 // -Xms1m -Xmx10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError性能

// -Xms1m -Xmx10m -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError
List<Object> listObject = new ArrayList<>();
for (int i = 0; i < 10; i++) {
System.out.println("i:" + i);
Byte[] bytes = new Byte[1 * 1024 * 1024];
listObject.add(bytes);
}
System.out.println("添加成功...");複製代碼

二、虛擬機棧溢出

錯誤緣由: java.lang.StackOverflowError 棧內存溢出測試

棧溢出 產生於遞歸調用,循環遍歷是不會的,可是循環方法裏面產生遞歸調用, 也會發生棧溢出。

解決辦法:設置線程最大調用深度

-Xss5m 設置最大調用深度

public class JvmDemo04 {
     private static int count;
     public static void count(){
        try {
             count++;
             count(); 
        } catch (Throwable e) {
            System.out.println("最大深度:"+count);
            e.printStackTrace();
        }
     }
     public static void main(String[] args) {
         count();
    }
}
複製代碼

三、內存溢出與內存泄漏區別

Java內存泄漏就是沒有及時清理內存垃圾,致使系統沒法再給你提供內存資源(內存資源耗盡);

而Java內存溢出就是你要求分配的內存超出了系統能給你的,系統不能知足需求,因而產生溢出。

內存溢出,這個好理解,說明存儲空間不夠大。就像倒水倒多了,從杯子上面溢出了來了同樣。

內存泄漏,原理是,使用過的內存空間沒有被及時釋放,長時間佔用內存,最終致使內存空間不足,而出現內存溢出。

3、垃圾收集器

一、串行與並行收集器

串行回收: JDK1.5前的默認算法 缺點是隻有一個線程,執行垃圾回收時程序中止的時間比較長

並行回收: 多個線程執行垃圾回收適合於吞吐量的系統,回收時系統會中止運行

二、serial收集器

串行收集器是最古老,最穩定以及效率高的收集器,可能會產生較長的停頓,只使用一個線程去回收。新生代、老年代使用串行回收;新生代複製算法、老年代標記-壓縮;垃圾收集的過程當中會Stop The World(服務暫停)

一個單線程的收集器,在進行垃圾收集時候,必須暫停其餘全部的工做線程直到它收集結束。

特色:CPU利用率最高,停頓時間即用戶等待時間比較長。

適用場景:小型應用

經過JVM參數-XX:+UseSerialGC可使用串行垃圾回收器。

三、ParNew收集器

ParNew收集器其實就是Serial收集器的多線程版本。新生代並行,老年代串行;新生代複製算法、老年代標記-壓縮

參數控制:-XX:+UseParNewGC ParNew收集器

-XX:ParallelGCThreads 限制線程數量

四、parallel 收集器

Parallel Scavenge收集器相似ParNew收集器,Parallel收集器更關注系統的吞吐量。能夠經過參數來打開自適應調節策略,虛擬機會根據當前系統的運行狀況收集性能監控信息,動態調整這些參數以提供最合適的停頓時間或最大的吞吐量;也能夠經過參數控制GC的時間不大於多少毫秒或者比例;新生代複製算法、老年代標記-壓縮

採用多線程來經過掃描並壓縮堆

特色:停頓時間短,回收效率高,對吞吐量要求高。

適用場景:大型應用,科學計算,大規模數據採集等。

經過JVM參數 XX:+USeParNewGC 打開併發標記掃描垃圾回收器。

五、cms收集器

CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間爲目標的收集器。目前很大一部分的Java應用都集中在互聯網站或B/S系統的服務端上,這類應用尤爲重視服務的響應速度,但願系統停頓時間最短,以給用戶帶來較好的體驗。

從名字(包含「Mark Sweep」)上就能夠看出CMS收集器是基於「標記-清除」算法實現的,它的運做過程相對於前面幾種收集器來講要更復雜一些,整個過程分爲4個步驟,包括:

  • 初始標記(CMS initial mark)
  • 併發標記(CMS concurrent mark)
  • 從新標記(CMS remark)
  • 併發清除(CMS concurrent sweep)

其中初始標記、從新標記這兩個步驟仍然須要「Stop The World」。初始標記僅僅只是標記一下GC Roots能直接關聯到的對象,速度很快,併發標記階段就是進行GC Roots Tracing的過程,而從新標記階段則是爲了修正併發標記期間,因用戶程序繼續運做而致使標記產生變更的那一部分對象的標記記錄,這個階段的停頓時間通常會比初始標記階段稍長一些,但遠比並發標記的時間短。

因爲整個過程當中耗時最長的併發標記和併發清除過程當中,收集器線程均可以與用戶線程一塊兒工做,因此整體上來講,CMS收集器的內存回收過程是與用戶線程一塊兒併發地執行。老年代收集器(新生代使用ParNew)

優勢:併發收集、低停頓

缺點:產生大量空間碎片、併發階段會下降吞吐量

採用「標記-清除」算法實現,使用多線程的算法去掃描堆,對發現未使用的對象進行回收。

  • (1)初始標記
  • (2)併發標記
  • (3)併發預處理
  • (4)從新標記
  • (5)併發清除
  • (6)併發重置
    特色:響應時間優先,減小垃圾收集停頓時間

適應場景:大型服務器等。

經過JVM參數 -XX:+UseConcMarkSweepGC設置

六、g1收集器

在G1中,堆被劃分紅 許多個連續的區域(region)。採用G1算法進行回收,吸取了CMS收集器特色。

特色:支持很大的堆,高吞吐量

  • --支持多CPU和垃圾回收線程
  • --在主線程暫停的狀況下,使用並行收集
  • --在主線程運行的狀況下,使用併發收集

實時目標:可配置在N毫秒內最多隻佔用M毫秒的時間進行垃圾回收

經過JVM參數 -XX:+UseG1GC 使用G1垃圾回收器

注意: 併發是指一個處理器同時處理多個任務。 

並行是指多個處理器或者是多核的處理器同時處理多個不一樣的任務。 

併發是邏輯上的同時發生(simultaneous),而並行是物理上的同時發生。

來個比喻:併發是一我的同時吃三個饅頭,而並行是三我的同時吃三個饅頭。 

4、Tomcat配置調優測試

一、Jmeter壓力測試工具

JMeter是一款在國外很是流行和受歡迎的開源性能測試工具,像LoadRunner 同樣,它也提供了一個利用本地Proxy Server(代理服務器)來錄製生成測試腳本的功能,可是這個功能並很差用。因此在本文中介紹一個更爲經常使用的方法——使用Badboy錄製生成 JMeter 腳本。

簡單的介紹一下Badboy。Badboy是一款不錯的Web自動化測試工具,若是你將它用於非商業用途,或者用於商業用途可是安裝Badboy 的機器數量不超過5臺,你是不須要爲它支付任何費用的。也許是一種推廣策略,Badboy提供了將Web測試腳本直接導出生成JMeter 腳本的功能,而且這個功能很是好用,也很是簡單。你能夠跟着下面的試驗步驟來邁出你在開源世界的第一步。

  1. 經過Badboy的官方網站下載Badboy的最新版本;
  2. 安裝Badboy。安裝過程同通常的Windows 應用程序沒有什麼區別,安裝完成後你能夠在桌面和Windows開始菜單中看到相應的快捷方式——若是找不到,能夠找一下Badboy安裝目錄下的Badboy.exe 文件,直接雙擊啓動Badboy;
  3. 啓動Badboy,你能夠看到下面的界面。
    file
    在地址欄(圖中紅色方框標註的部分)中輸入你須要錄製的Web應用的URL——這裏咱們以http://www.yahoo.com 爲例,並點擊GO 按鈕開始錄製。
  4. 開始錄製後,你能夠直接在Badboy內嵌的瀏覽器(主界面的右側)中對被測應用進行操做,全部的操做都會被記錄在主界面左側的編輯窗口中——在這個試驗中,咱們在Yahoo的搜索引擎中輸入 JMeter 進行搜索。不過你將看到,錄製下來的腳本並非一行行的代碼,而是一個個Web對象——這就有點像LoadRunner的VuGen中的Tree View視圖;
  5. 錄製完成後,點擊工具欄中的「中止錄製」按鈕,完成腳本的錄製;
  6. 選擇「File -> Export to JMeter」菜單,填寫文件名「login_mantis.jmx」,將錄製好腳本導出爲JMeter腳本格式。也能夠選擇「File -> Save」菜單保存爲Badboy腳本;
  7. 啓動JMeter並打開剛剛生成的測試腳本。

二、什麼是吞吐量

QPS:Queries Per Second意思是「每秒查詢率」,是一臺服務器每秒可以相應的查詢次數,是對一個特定的查詢服務器在規定時間內所處理流量多少的衡量標準。

三、測試

3.一、測試串行吞吐量

-XX:+PrintGCDetails -Xmx32M -Xms1M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseSerialGC
-XX:PermSize=32M
GC 回收次數25次 吞吐量4662 

--> 堆的初始值和堆的最大一致
加大初始堆內存大小-Xms1M 修改成32m
GC 回收次數7次 吞吐量5144複製代碼

3.二、擴大堆的內存

-XX:+PrintGCDetails -Xmx512M -Xms32M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseSerialGC
-XX:PermSize=32M
GC 回收次數6次 吞吐量5141
結論:垃圾回收次數和設置最大堆內存大小無關,只和初始內存有關係。
初始內存會影響吞吐量。複製代碼

3.三、調整初始堆

-XX:+PrintGCDetails -Xmx512M –Xms512M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseSerialGC
-XX:PermSize=32M
GC回收次數0次 吞吐量6561次
結論:堆的初始值和最大堆內存一致,而且初始堆越大就會高。複製代碼

3.四、並行回收(UseParNewGC)

-XX:+PrintGCDetails -Xmx512M -Xms512M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseParNewGC
-XX:PermSize=32M
GC回收0次 吞吐量6800複製代碼

3.五、CMS收集器

-XX:+PrintGCDetails -Xmx512M -Xms512M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseConcMarkSweepGC 
-XX:PermSize=32M複製代碼

3.六、G1回收方式

-XX:+PrintGCDetails -Xmx512M -Xms512M
-XX:+HeapDumpOnOutOfMemoryError
-XX:+UseG1GC
-XX:PermSize=32M複製代碼

三、調優總結

初始堆值和最大堆內存內存越大,吞吐量就越高。

最好使用並行收集器,由於並行收集器速度比串行吞吐量高,速度快。

設置堆內存新生代的比例和老年代的比例最好爲1:2或者1:3。

減小GC對老年代的回收。

我的博客 蝸牛

相關文章
相關標籤/搜索