深入瞭解Java虛擬機:JVM調優

初探

  • Java代碼運行,Java源文件(.java)-- > javac編譯 -->字節碼文件(.class)–> JVM --> 計算機底層指令和硬件
  • jvm,Java虛擬機,不同的操作系統有不同版本的JVM虛擬機。JVM從軟件層面,隱藏了底層技術實現的複雜性,屏蔽了不同機器不同操作系統的底層細節,保證Java代碼,編寫一次,到處執行。Write Once,Run Anywhere.

JDK、JRE與JVM

  • Java,是一種面向對象的編程語言,屬於高級語言。1995年,Java之父,詹姆斯·高斯林(高司令),Oak --> Java。
  • JDK Java開發工具包,包含JRE。
  • JRE Java運行時環境,包含JVM。
  • JVM Java虛擬機,包含運行時數據區、執行引擎、本地庫接口等。

內存結構

  • 堆和方法區,是線程共享區
  • 棧,本地方法棧、程序計數器,是線程獨佔區

  • new的對象都放在堆裏
年輕代(佔堆內存的1/3)
  • Eden,佔年輕代的80%,程序數據先往Eden裏寫入,當Eden內存用完時,觸發Minor GC,垃圾對象被清理,非垃圾對象被複制到Survivor區域,這些對象的分代年齡加1。
  • Survivor,佔年輕代的20%,分爲2部分,各佔10%;當觸發Minor GC 時,Survivor區域裏的垃圾對象也會被清理,非垃圾對象在Survivor的兩個分區相互移動,這些對象的分代年齡繼續加1。
  • S0 1/3 * 10%
  • S1 1/3 * 10%
老年代(佔堆內存的2/3)
  • 大對象直接進入老年代,可以通過 -XX:PretenureSizeThreshold 設置,超過這個值,對象直接在Old區分配內存。這個參數只在Serial和ParNew2個收集器下有效。
  • 長期存活的對象進入老年代。當Survivor區裏的非垃圾對象分代年齡達到閾值(默認15,可通過 -XX:MaxTenuringThreshold 來設置),就會將這些對象移入老年代。
  • 對象動態年齡判斷。Minor GC時,當一批對象的總大小大於Survivor區內存大小的50%(可通過 -XX:TargetSurvivorRatio指定),會被放入Old區分配內存。
  • Minor GC後,Survivor區放不下,多餘的部分也會放入到Old區域。
  • 當老年代內存被佔用完,就會觸發full GC。
  • 當full GC 後,old區域空間還是不夠分配,程序拋出異常OutOfMemoryError: Java heap space。

  • 棧,遵循後進先出原則
  • 一個方法,分配一個棧幀
  • 局部變量表,存儲方法的局部變量,存儲變量的指針
  • 操作數棧,存儲變量的值
  • 動態鏈接
  • 方法出口,方法運行結束,返回主線程

程序計數器

  • 當前線程正在運行的代碼的位置(行號)

方法區

  • 存儲類信息,類的常量和靜態變量

本地方法棧

  • native 本地方法,調用本地系統的接口或者本地外部c程序的接口

垃圾回收機制

  • GC Roots根節點:線程棧的本地變量,靜態變量、本地方法棧的變量等等
  • 講“GC Roots”對象作爲起點,從這些節點開始搜索引用的對象,找到的對象標記爲非垃圾對象,其餘未標記的對象都是垃圾對象。
  • Eden滿時觸發Minor GC
  • Old滿時觸發full GC

性能監控工具

jconsole

  • java啓動命令添加jvm參數 -XX:+HeapDumpOnOutOfMemoryError 可以輸出內存溢出時的堆棧

jmap

  • 查看堆內存使用情況
  • 命令 : jmap -heap

jvisualvm

  • java 6,7,8自帶的jvm調優工具
  • java9及以後,就停止使用java VisualVM了,改用Graal VisualVM了
  • 查看heap堆得Eden、Old,需要安裝一個Visual GC插件。安裝方法很簡單,找到jdk目錄的bin下面,打開jvisualvm.exe,然後 工具-》插件,選擇Visual GC即可,在線安裝如果不行,可以先下載再安裝。
    jvisualVM界面

性能調優案例

概念

  • STW : Java中Stop-The-World機制.
  • 執行垃圾收集算法時,Java應用程序的其他所有線程都被掛起,只執行垃圾收集。這是Java中一種全局暫停現象,會給程序使用者帶來非常不好的體驗(卡頓)。
  • jvm調優,就是爲了減少full GC 的次數,減少STW時間,發揮出機器原本就有的性能,使程序更加穩定高效的運行,最終給程序使用者帶來更好的使用體驗。

部分JVM參數

  • Xms 設置java程序啓動時堆內存128M(默認爲物理內存1/64,且小於1G)
  • Xmx 設置最大堆內存256M,超出後會出現 OutOfMemoryError(默認爲物理內存1/64,且小於1G)
  • Xmn 堆內存,新生代區域大小
  • Xss 設置線程棧的大小 1M(默認1M)
  • XX:MinHeapFreeRatio=40:設置堆空間最小空閒比例(默認40)(當-Xmx與-Xms相等時,該配置無效)
  • XX:MaxHeapFreeRatio=70:設置堆空間最大空閒比例(默認70)(當-Xmx與-Xms相等時,該配置無效)
  • XX:NewRatio=2:設置年輕代與年老代的比例爲2:1
  • XX:SurvivorRatio=8:設置年輕代中eden區與survivor區的比例爲8:1:1
  • XX:MetaspaceSize=64M:設置元數據空間初始大小(取代-XX:PermSize)
  • XX:MaxMetaspaceSize=128M:設置元數據空間最大值(取代之前-XX:MaxPermSize)
  • XX:TargetSurvivorRatio=50:設置survivor區使用率。當survivor區達到50%時,將對象送入老年代

調優

  • 可以根據實際需要分配堆內存大小,運行程序,觸發full GC,再根據實際情況調優
  • 如果條件足夠,可以多分配點內存。可以適當調大Eden,讓更少的臨時對象進入Old區。
  • 可以考慮使用G1
  • 可以參考這篇博客,講的比較詳細。
發佈了83 篇原創文章 · 獲贊 75 · 訪問量 31萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章