初探
- 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即可,在線安裝如果不行,可以先下載再安裝。
性能調優案例
概念
- 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
- 可以參考這篇博客,講的比較詳細。