JVM系列【6】GC與調優3

JVM系列筆記目錄

  • 虛擬機的基礎概念
  • class文件結構
  • class文件加載過程
  • jvm內存模型
  • JVM經常使用指令
  • GC與調優

調優前的基礎概念

  1. 吞吐量:用戶代碼時間 /(用戶代碼執行時間 + 垃圾回收時間)
  2. 響應時間:STW越短,響應時間越好
  3. 所謂調優,首先肯定,追求啥?吞吐量優先,仍是響應時間優先?仍是在知足必定的響應時間的狀況下,要求達到多大的吞吐量。如科學計算、數據挖掘:吞吐量優先;網站、GU、 API 等追求響應時間。

什麼是調優

  1. 根據需求進行JVM規劃和預調優
  2. 優化JVM運行環境(慢、卡頓)
  3. 解決JVM運行過程當中出現的各類問題(如OOM)
  • 根據需求進行JVM規劃和預調優

    調優通常來講,從業務場景開始,沒有業務場景的調優都是耍流氓;無監控 (壓力測試,能看到結果),不調優。java

    步驟面試

    1. ​ 熟悉業務場景
    2. 選擇回收器組合,沒有最好的GC,只有最適合的GC。追求響應時間或停頓時間選擇CMS、G一、ZGC追求吞吐量 可選擇PS。
    3. 計算內存需求(經驗值 1.5G -16G)
    4. 選定CPU(越高越好)
    5. 設定年代大小,升級年代
    6. 設定日誌參數,日誌文件全放一個?10T日誌怎麼查。能夠設置滾動日誌如 -Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause, 或是天天產生一個日誌文件。
    7. 觀察日誌狀況

    提供一個簡單的案例分析服務器

    案例1:垂直電商,最高每日百萬訂單,處理訂單系統須要什麼樣的服務器配置?

    這個問題比較業餘,由於不少不一樣的服務器配置都能支撐(1.5G -16G)。能夠具體分析:一天中特定的高峯期1小時有360000訂單集, 1000個訂單/秒,能夠根據經驗值估算須要的內存配置。若是非要要計算,能夠這麼算:一個訂單產生須要多少內存?512K * 1000,須要500M內存。多線程

    從另外專業的角度考慮:要求響應時間100ms,這種狀況下能夠經過壓測的方式找到符合的服務器配置。運維

  • 優化JVM運行環境(慢、卡頓)
    1. 提供一個簡單的案例分析。jvm

      有一個50萬PV的資料類網站(從磁盤提取文檔到內存)原服務器32位,1.5G的堆.用戶反饋網站比較緩慢,所以公司決定升級。新的服務器爲64位,16G的堆內存,結果用戶反饋卡頓十分嚴重,反而比之前效率更低了。工具

      1. 爲何原網站慢?不少用戶瀏覽數據,不少數據load到內存,內存不足,頻繁GC,STW長,響應時間變慢。
      2. 爲何會更卡頓?內存越大,FGC時間越長
      3. 如何解決?能夠換垃圾回收器,如從PS 換爲PN + CMS 或者是1.8以上的直接用G1。
    2. 系統CPU常常100%,如何調優?(面試高頻)測試

      CPU100%那麼必定有線程在佔用系統資源,優化

      1. 找出哪一個進程cpu高(top)
      2. 該進程中的哪一個線程cpu高(top -Hp)
      3. 導出該線程的堆棧 (jstack)
      4. 查找哪一個方法(棧幀)消耗時間長 (jstack)
      5. 對比工做線程佔比高仍是垃圾回收線程佔比高
    3. 系統內存飆高,如何調優(面試高頻)網站

      思路: 導出堆內存(jmap); 使用工具如(jhat jvisualvm mat jprofiler)分析
  • 解決JVM運行過程當中出現的各類問題

    提供一個測試案例來講明分析過程和經常使用的工具,代碼以下:

    /**

*/

public class T15_FullGC_Problem01 {

private static class CardInfo {
      BigDecimal price = new BigDecimal(0.0);
      String name = "張三";
      int age = 5;
      Date birthdate = new Date();

      public void m() {}
  }

  private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(50,
          new ThreadPoolExecutor.DiscardOldestPolicy());

  public static void main(String[] args) throws Exception {
      executor.setMaximumPoolSize(50);

      for (;;){
          modelFit();
          Thread.sleep(100);
      }
  }

  private static void modelFit(){
      List<CardInfo> taskList = getAllCardInfo();
      taskList.forEach(info -> {
          // do something
          executor.scheduleWithFixedDelay(() -> {
              //do sth with info
              info.m();

          }, 2, 3, TimeUnit.SECONDS);
      });
  }

  private static List<CardInfo> getAllCardInfo(){
      List<CardInfo> taskList = new ArrayList<>();

      for (int i = 0; i < 100; i++) {
          CardInfo ci = new CardInfo();
          taskList.add(ci);
      }

      return taskList;
  }

}

1. 啓動命令`java -Xms20M -Xmx20M -XX:+UseParallelGC -XX:+HeapDumpOnOutOfMemoryError T15_FullGC_Problem01`

2. 通常是運維團隊首先受到報警信息(CPU、Memory)

3. top命令觀察到問題:內存不斷增加,CPU佔用率居高不下

4. top -Hp 觀察進程中的線程,哪一個線程CPU和內存佔比高

5. jps定位具體java進程;jstack  pid  定位線程情況,重點關注:WAITING BLOCKED

   >  waiting on <0x0000000088ca3310> (a java.lang.Object)
   >    假若有一個進程中100個線程,不少線程都在waiting on <xx> ,必定要找到是哪一個線程持有這把鎖。   怎麼找?搜索jstack dump的信息,找<xx> ,看哪一個線程持有這把鎖處於RUNNABLE狀態。

6. jinfo pid 查看JVM的狀況,通常用處不大。

7. 經過jstat -gc 動態觀察gc狀況;或是閱讀GC日誌發現頻繁GC;或是經過arthas觀察gc狀況。

8. 在線定位,查找有多少對象產生,注意大量的對象,使用`jmap -histo pid |head -20`

9. `jmap -dump:format=b,file=xxx pid `能夠在線堆轉儲,可是要慎重影響很大。

   > 線上系統內存特別大,jmap執行期間對進程產生很大影響,甚至卡頓(電商不適合)。
   >
   > 如何解決? 啓動時候設定參數HeapDumpOnOutOfMemoryError,OOM的 時候會自動產生堆轉儲文件;若是線上不少服務器備份(高可用),停掉這臺服務器對其它服務沒影響也能夠在線堆轉儲;在線定位也能夠用阿里的arthas。

10. 使用MAT/jhat/jvisualvm 進行dump文件分析。

    > 建議使用MAT/jvisualvm 裝入分析,界面友好且支持複雜查詢

11. 最難的一點:定位到代碼中的問題

    > 示例代碼的問題是:線程池使用不當引發OOM;不停new CardInfo對象不停地起定時線程去處理,致使這些對象愈來愈多
相關文章
相關標籤/搜索