十二:JVM調優及參數配置

JVM 的參數類型

  • 標配參數
    • -version
    • -help
  • X 參數(瞭解)
    • -Xint:解釋執行
    • -Xcomp:第一次使用就編譯成本地代碼
    • -Xmixed:混合模式
  • XX 參數
    • Boolean 類型:-XX:+ 或者 - 某個屬性值(+ 表示開啓,- 表示關閉)
      • -XX:+PrintGCDetails:打印 GC 收集細節
    • KV 設置類型:-XX:key=value
      • -XX:MetaspaceSize=128m
      • -XX:MaxTenuringThreshold=15
    • jinfo 舉例,如何查看當前運行程序的配置
public class HelloGC {
    public static void main(String[] args) {
        System.out.println("hello GC...");
        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

我們可以使用 jps -l 命令,查出進程 id

  • 在使用 jinfo -flag PrintGCDetails 1933 命令查看

    -XX:-PrintGCDetails
    

    可以看出默認是不打印 GC 收集細節
    也可是使用jinfo -flags 1933 查看所以的參數

  • 兩個經典參數:-Xms 和 - Xmx(如 -Xms1024m)

    • -Xms 等價於 -XX:InitialHeapSize
    • -Xmx 等價於 -XX:MaxHeapSize

查看 JVM 默認值

  • 查看初始默認值:-XX:+PrintFlagsInitial

  • 查看修改更新:-XX:+PrintFlagsFinal

    = 與 := 的區別是,一個是默認,一個是人爲改變或者 jvm 加載時改變的參數

  • 打印命令行參數(可以看默認垃圾回收器):-XX:+PrintCommandLineFlags

常用配置

  • -Xms

    • 初始大小內存,默認爲物理內存 1/64
    • 等價於 -XX:InitialHeapSize
  • -Xmx

    • 最大分配內存,默認爲物理內存的 1/4
    • 等價於 -XX:MaxHeapSize
    • 生產中-Xmx與-Xms設置一樣大小。因爲默認空餘堆內存小於40%時JVM就會增大堆內存直到設置的最大值;空餘堆內存70%時,JVM就會減少堆內存直到設置的最小值。
  • -Xss

    • 設置單個線程棧的大小,一般默認爲 512-1024k
    • 等價於 -XX:ThreadStackSize
  • -XX:MetaspaceSize

    • 設置元空間大小(元空間的本質和永久代類似,都是對 JVM 規範中的方法區的實現,不過元空間於永久代之間最大區別在於,元空間並不在虛擬中,而是使用本地內存,因此默認情況下,元空間的大小僅受本地內存限制)
    • 元空間默認比較小,我們可以調大一點
  • -XX:+PrintGCDetails

    • 輸出詳細 GC 收集日誌信息

      • 設置 JVM 參數爲: -Xms10m -Xmx10m -XX:+PrintGCDetails

      • 代碼

        public class HelloGC {
            public static void main(String[] args) {
                byte[] bytes = new byte[20 * 1024 * 1024];
            }
        }
        
      • 打印結果

    • GC(minor日誌)
      在這裏插入圖片描述

    • FullGC
      在這裏插入圖片描述

  • -Xmn

    • 設置年輕代的大小
    • 整個JVM內存大小=年輕代大小 + 年老代大小 + (持久代大小),持久代一般固定大小爲64m,所以增大年輕代後,將會減小年老代大小。此值對系統性能影響較大,Sun官方推薦配置爲整個堆的3/8。
  • -XX:SurvivorRatio

    • 設置新生代中 eden 和 S0/S1 空間比例
    • 默認 -XX:SurvivorRatio=8,Eden : S0 : S1 = 8 : 1 : 1
    • -XX:SurvivorRatio=eden/from=eden/to
  • -XX:NewRatio

    • 配置年輕代和老年代在堆結構的佔比
    • 默認 -XX:NewRatio=2 新生代佔1,老年代佔2,年輕代佔整個堆的 1/3
    • -XX:NewRatio=老年代/新生代
  • -XX:MaxTenuringThreshold(必選)

    • 設置垃圾最大年齡,默認15
  • -XX:+AggresslveOps(必選)

  • jdk自帶的魔法屬性,積極的生猛的;可以將jdk優化後的新特性自動注入

  • -XX:+UseBiasedLocking(必選)

    • 啓用一個優化的線程鎖,對於高併發訪問很重要,太多的請求忙不過來它自動優化;對於格子長短不一的請求,出現阻塞,排隊的現象,它也自動優化。
  • -XX:+DisableExplicitGC(必選)

    • 禁止代碼中顯示調用GC
  • -Djava.awt.headess=true

    • 避免linux環境下圖形化界面無法顯示的問題
  • -XX:+UseCMSCompactAtFullCollection(必選)

    • 使用併發收集器時,開啓對年老代的壓縮
  • -XX:CMSFullGCsBeforeCompaction=50(必選)

    • 上面配置開啓的情況下,這裏設置多少次Full GC後,對年老代進行壓縮
  • -XX:+CMSparalleRemarkEnabled(必選)

    • 降低標記停頓
  • -XX:LargePageSizeInBytes=128m(必選)

    • JVM內存分頁
  • -XX:+UseFastAccessorMethods

    • 優化產生的 BIN,執行過程提速
  • -XX:+UseCMSInitiatingOccupancyOnly

    • 只有在老年代的使用率達到閾值時纔會觸發CMS,一般和-XX:CMSInitiatingOccupancyFraction=68(默認,即當老年代的空間使用率達到68%時會執行一次cms回收)配合使用。
  • -XX:+DoEscapeAnalysis

    • 逃逸分析棧上分配,意思是方法內局部變量(未發生逃逸)生成的實例在棧上分配,不用在堆中分配,分配完成後,繼續在調用棧內執行,最後線程結束,棧空間被回收,局部變量對象也被回收。
    • 一般生成的實例都是放在堆中的,然後把實例的指針或引用壓入棧中
  • -XX:+EliminateAllocations (配合逃逸分析)

    • 開啓變量替換
    • 標量:即不可被進一步分解的量,而JAVA的基本數據類型就是標量(如:int,long等基本數據類型以及reference類型等),標量的對立就是可以被進一步分解的量,而這種量稱之爲聚合量。而在JAVA中對象就是可以被進一步分解的聚合量。
    • 替換: 通過逃逸分析確定該對象不會被外部訪問,並且對象可以被進一步分解時,JVM不會創建該對象,而會將該對象成員變量分解若干個被這個方法使用的成員變量所代替。這些代替的成員變量在棧幀或寄存器上分配空間。
  • -XX:+EliminateLocks (配合逃逸分析)

    • 同步消除
    • 同步消除是java虛擬機提供的一種優化技術。通過逃逸分析,可以確定一個對象是否會被其他線程進行訪問。如果你定義的類的方法上有同步鎖,但在運行時,卻只有一個線程在訪問,此時逃逸分析後的機器碼,會去掉同步鎖運行,這就是沒有出現線程逃逸的情況。那該對象的讀寫就不會存在資源的競爭,不存在資源的競爭,則可以消除對該對象的同步鎖。
  • -XX:+UseTLAB

    • TLAB全稱ThreadLocalAllocBuffer,是線程的一塊私有內存,如果設置了虛擬機參數 -XX:UseTLAB,在線程初始化時,同時也會申請一塊指定大小的內存,只給當前線程使用,這樣每個線程都單獨擁有一個Buffer,如果需要分配內存,就在自己的Buffer上分配,這樣就不存在競爭的情況,可以大大提升分配效率,當Buffer容量不夠的時候,再重新從Eden區域申請一塊繼續使用,這個申請動作還是需要原子操作的。
    • -XX:TLABSize= 表示,設置TLAB大小
    • -XX:+ResizeTLAB 是否啓動動態修改
    • -XX:TLABRefillWasteFraction 表示,設置進入TLAB空間,單個對象大小是一個比例值,默認爲64 如果,對象小於整個空間的1/64,則放在TLAB區 如果,對象大於整個空間的1/64,則放在堆區
  • -XX:+PrintVMOptions

    • 打印虛擬機接收到的命令行顯式參數
  • -XX:+PrintCommandLineFlags

    • 打印虛擬機接收到的命令行顯式和隱式參數,隱式參數可能是虛擬機啓動時自動設置的
  • -XX:MaxDirectMemorySize

    • 設置最大可用直接內存,默認是最大堆空間
    • 直接內存適合申請次數較少、訪問頻繁的場合

GC與垃圾回收器

  • 四種 GC 垃圾回收算法
    • 引用計數
    • 複製回收
    • 標記清除
    • 標記整理
  • GC 算法是內存回收的方法論,垃圾收集其就是算法的落實的實現。
  • 目前爲止還沒有完美的收集器的出現,更加沒有萬能的收集器,只是針對具體應用最適合的收集器,進行分代收集。
  • 串行垃圾回收器(Serial)
    • 它爲單線程環境設計且只使用一個線程進行垃圾回收,會暫停所有的用戶線程,所以不適合服務環境。
  • 並行垃圾回收器(Parallel)
    • 多個垃圾收集線程並行工作,此時用戶線程是暫停的,用於科學計算、大數據處理等弱交互場景。
  • 併發垃圾回收器(CMS)
    • 用戶線程和垃圾收集線程同時執行(不一定是並行,可能是交替執行),不需要停頓用戶線程,互聯網公司多用它,適用對相應時間有要求的場景。
  • G1 垃圾回收器
    • G1 垃圾回收器將堆內存分割成不同的區域然後併發的對其進行垃圾回收。

查看默認的垃圾回收器

  • 怎麼查看服務器默認垃圾收集器是哪個?
    • Java -XX:+PrintCommandLineFlags
  • Java 的 GC 回收的類型主要有:
    • UseSerialGC,UseParallelGC,UseConcMarkSweepGC,UseParNewGC,UseParallelOldGC,UseG1GC, SerialOldGC
    • Java 8 以後基本不使用 Serial Old
  • 垃圾收集器(紅叉部分不再推薦使用)
    在這裏插入圖片描述
  • 參數說明(GC日誌中術語)
    • DefNew : Default New Generation
    • Tenured : Old
    • ParNew : Parallel New Generation
    • PSYoungGen : Parallel Scavenge
    • ParOldGen : Parallel Old Generation
  • Server/Client 模式分別是什麼意思
    • 最主要的差別在於:-Server模式啓動時,速度較慢,但是一旦運行起來後,性能將會有很大的提升。
    • 當虛擬機運行在-client模式的時候,使用的是一個代號爲C1的輕量級編譯器, 而-server模式啓動的虛擬機採用相對重量級,代號爲C2的編譯器,C2比C1編譯器編譯的相對徹底,服務起來之後,性能更高。
    • 所以通常用於做服務器的時候我們用服務端模式,如果你的電腦只是運行一下java程序,就客戶端模式就可以了。當然這些都是我們做程序優化程序才需要這些東西的,普通人並不關注這些專業的東西了。其實服務器模式即使編譯更徹底,然後垃圾回收優化更好,這當然喫的內存要多點相對於客戶端模式。
  • 新生代
    • 串行 GC (Serial/ Serital Copying)
      • -XX:+UseSerialGC 可以指定新生代和老年代都是用串行收集器;client模式下它是默認的收集器;獨佔式單線程垃圾回收
    • 並行 GC (ParNew)
      • 當使用-XX:+UseparNewGC時,工作線程可以使用 -XX:ParallelGCThreads來指定,CPU數量小於8該值與CPU數量相等;反之大於可設置爲 3+((5*cpu)/8)
    • 並行回收 GC (Parallel/ Parallel Scanvenge)非常關注系統的吞吐量
      • -XX:MaxGCPauseMillis:設置垃圾收集最大停頓時間,是一個大於0的數,當ParallelGC工作時,會盡可能吧停頓時間控制在這個範圍內;若數值過小會導致GC頻繁,從而增加了垃圾回收總時間,降低了吞吐量。
      • -XX:GCTimeRatio:設置吞吐量,是一個0–100之間的整數;系統將不會花費超過 **1+(1+n)**的時間用於垃圾回收;默認值99。
  • 老年代
    • 串行 GC (Serial Old/ Serial MSC)
    • 並行 GC (Parallel Old/ Parallel MSC)
    • 併發標記清除 GC (CMS)
      • 是一種以獲取最短回收停頓時間爲目標的收集器,適合應用在互聯網站或者 B/S 系統的服務器上,這個類應用尤其重視服務器的響應速度,希望系統停頓時間最短。
      • CMS 非常適合堆內存大、CPU 核數多的服務器端應用,也是 G1 出現之前大型應用首選收集器。
      • 併發停頓比較少,併發指的是與用戶線程一起執行。
      • 過程
        • 初始標記(initail mark):只是標記一下 GC Roots 能直接關聯的對象,速度很快,需要暫停所有的工作線程
        • 併發標記(concurrent mark 和用戶線程一起):進行 GC Roots 的跟蹤過程,和用戶線程一起工作,不需要暫停工作線程。
        • 預清理:清理前準備以及控制停頓時間。可以通過 -XX:+CMSPrecleaningEnabled控制開啓與關閉。預清理是併發的,除了爲正式清理做準備和檢查外,這個階段還會嘗試控制一次停頓時間。由於重新標記是獨佔cpu的,若新生代gc後,立即觸發重新標記,那麼一次停頓時的時間很長。爲避免這種情況,預清理時會刻意等待一次新生代gc的發生,然後根據歷史性能數據預測下一次新生代gc的時間,然後在當前時刻與預測時間的中間時刻景進行重新標記。這樣儘量避免新生代gc與重新標記重合,從而減少停頓時間。
        • 重新標記(remark):爲了修正在併發標記期間,因用戶程序繼續運行而導致標記產生變動的那一部分對象的標記記錄,仍然需要暫停所有的工作線程。
        • 併發清除(concurrent sweep 和用戶線程一起):清除 GC 不可達對象,和用戶線程一起工作,不需要暫停工作線程,基於標記結果,直接清除。由於耗時最長的併發標記和併發清除過程中,垃圾收集線程和用戶線程可以一起併發工作,所以總體來看 CMS 收集器的內存回收和用戶線程是一起併發地執行。
        • 併發重置
      • 優缺點
        • 優點:併發收集停頓低
        • 缺點:併發執行對 CPU 資源壓力大,採用的標記清除算法會導致大量碎片
      • 由於併發進行, CMS 在收集與應用線程會同時增加對堆內存的佔用,也就是說,CMS 必須要在老年代堆用盡之前完成垃圾回收,否者 CMS 回收失敗,將觸發擔保機制,串行老年代收集器將會以 STW 的方式進行一次 GC,從而造成較大的停頓時間。
      • 標記清除算法無法整理空間碎片,老年代空間會隨着應用時長被逐漸耗盡,最後將不得不通過擔保機制對堆內存進行壓縮。CMS 也提供了參數 -XX:CMSFullGCsBeForeCompaction (默認0,即每次都進行內存整理) 來指定多少次 CMS 收集之後,進行一次壓縮整理空間碎片。
      • CMS參數設置
        • 併發線程數量:-XX:ConcGCThreads或-XX:ParallelGCThreadsCMS默認的併發線程數量((ParallelGCThreads+3)/4)
        • 堆內存使用率的閥值:-XX:CMSInitiatingOccupancyFraction默認68.即當老年代的空間使用率達到68%時會執行一次cms回收。
        • 回收Perm區Class數據:-XX:+CMSClassUnloadingEnabled
  • 垃圾收集器配置代碼總結
    • 配置新生代收集器,老年代收集器會自動配置上。
      1558237229584
  • 如何選擇垃圾收集器
    • 單 CPU 或者小內存,單機程序:-XX:UseSerialGC
    • 多 CPU 需要最大吞吐量,如後臺計算型應用:-XX:UseParallelGC 或者 -XX:UseParallelOldGC
    • 多 CPU 追求低停頓時間,需要快速響應,如互聯網應用:-XX:+UseConcMarkSweepGC

G1垃圾收集器

  • 以前收集器的特點

    • 年輕代和老年代是各自獨立且連續的內存塊
    • 年輕代收集器使用 eden + S0 + S1 進行復制算法
    • 老年代收集必須掃描整個老年代區域
    • 都是以儘可能的少而快速地執行 GC 爲設計原則
  • G1 是什麼

    • G1 是一種面向服務端的垃圾收集器,應用在多核處理器和大容量內存環境中,在實現高吞吐量的同時,儘可能的滿足垃圾收集器的暫停時間要求。
    • 像 CMS 收集器一樣,能與應用程序線程併發執行,整理空閒空間更快,需要更多的時間來預測 GC 停頓時間,不希望犧牲大量的吞吐性能,不需要更大的 JAVA Heap。
    • G1 收集器的設計目的是取代 CMS 收集器,同時與 CMS 相比,G1 垃圾收集器是一個有整理內存過程的垃圾收集器,不會產生很多內存碎片。G1 的 Stop The World 更可控,G1 在停頓上添加了預測機制,用戶可以指定期望的停頓時間。
    • G1 是在 2012 年纔在 jdk.1.7u4 中可以使用,在 jdk9 中將 G1 變成默認垃圾收集器來代替 CMS。它是以款面向服務應用的收集器。
    • 主要改變是 Eden、Survivor 和 Tenured 等內存區域不再是連續的,而是變成了一個個大小一樣的 region,每個 region 從 1M 到 32M 不等,一個 region 有可能屬於 Eden、Survivor 或者 Tenured 內存區域。
  • 特點

    • 並行性:G1在回收期間,可以有多個gc線程同時工作,有效利用多核計算能力。
    • 併發性:G1可以與應用程序交替執行,部分工作可以同時執行,不會再整個回收期間完全阻塞應用程序。
    • 分代GC:G1是一個分代收集器,同時兼顧年輕代和老年代。
    • 空間整理:G1在收集期間,會是黨的對象移動,不像CMS只是簡單地標記清理對象,在若干次gc之後才進行一次碎片整理;而G1不同,在每次gc之後都會有效的複製對象,減少空間碎片。
    • 可預見性:由於分區的原因,G1可以選取部分區域進行內存回收,這樣縮小了範圍,對全局停頓也有較好的控制。
  • 底層原理

    • Region 區域化垃圾收集器:最大好處是化整爲零,避免全內存掃描,只需要按照區域來進行掃描即可。

    • Region

      5611237-f643066bd97c7703
      G1的內存結構和傳統的內存空間劃分有比較的不同。G1將內存劃分成了多個大小相等的Region(默認是512K),Region邏輯上連續,物理內存地址不連續。同時每個Region被標記成E、S、O、H,分別表示Eden、Survivor、Old、Humongous。其中E、S屬於年輕代,O與H屬於老年代。
      H表示Humongous。從字面上就可以理解表示大的對象(下面簡稱H對象)。當分配的對象大於等於Region大小的一半的時候就會被認爲是巨型對象。H對象默認分配在老年代,可以防止GC的時候大對象的內存拷貝。通過如果發現堆內存容不下H對象的時候,會觸發一次GC操作。

    • 回收步驟

    • 四步過程

      在這裏插入圖片描述

    • 初始標記:標記從根節點直接可達的對象,會伴隨一次新生代GC,會全局停頓,應用程序線程也會停止。

    • 跟區域掃描:初始化標記之後,eden被清空,並且存活的對象會被移動到survivor區。在這個階段,將掃描由survivor區直接可達的老年區域,並標記這些直接可達的對象。由於跟區域掃描和新生代GC不能同時執行,若此時要進行新生代GC,就需要到等待跟區域掃描之後進行,因此會比較耗時。

    • 併發標記:和CMS一樣併發標記將掃描並檢查整個堆的存活對象,這是個併發的過程,並且這個過程可以被一次新生代GC打斷。

    • 重新標記:和CMS一樣,重新標記也會使應用程序停頓。由於此過程中,應用程序依然運行,因此標記結果可能需要修正,所以次過程是對上一次標記的補充。

    • 獨佔清理:這個過程會引起停頓。他講計算各個區域的存活對象和GC回收比例進行排序,識別可供混合回收的區域。

    • 併發清理:此過程會識別並清理完全空閒的區域,不會引起停頓。

Linux指標命令

  • 整機:top

在這裏插入圖片描述

  • CPU:vmstat
    在這裏插入圖片描述

  • 內存:free

  • 硬盤:df

  • 磁盤IO:iostat

  • 網絡IO:ifstat

  • cpu信息

    • 總核數 = 物理CPU個數 X 每顆物理CPU的核數

    • 總邏輯CPU數 = 物理CPU個數 X 每顆物理CPU的核數 X 超線程數

    • 查看物理CPU個數

      • cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l
        
    • 查看每個物理CPU中core的個數(即核數)

      • cat /proc/cpuinfo| grep "cpu cores"| uniq
        

        查看邏輯CPU的個數

      • cat /proc/cpuinfo| grep "processor"| wc -l
        

常用GC參數

在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章