JVM虛擬機基礎知識
1. Java的發展
Java之父:詹姆斯·高斯林
2. Java的技術體系
- Java 程序設計語言
- JVM
- class文件格式
- 編譯器
- Java API
- 第三方Java類庫
Java SE(Java Standard edition)
Java ME(Micro Edition)
Java EE(Java Enterprise Edition)
3. JVM的安裝
4. JDK、JRE、JVM的關系
JDK(Java Development Kit)
JRE(Java Runtime Environment)
JVM(Java Virtual Machine)
官方結構圖:https://docs.oracle.com/javase/8/docs/
5.Java8的新特性
- 引入lambda表式式
- Nashorn JavaScript引擎,使用Metaspace 代替PermGen space
- Date API
- 更好的類型判斷
6.Java 虛擬機產品
- Sun Classic VM :第一款商用虛擬機,只能使用純解釋器的方式來執行Java代碼。已被淘汰
- Exact VM (Exact Memory Management) : 編譯器和解釋器混合工作以及兩級及時編譯器,只在solaris平臺發布
- HotSpot VM: Longview Technologies-->SUN-->Oracle
- KVM(Kilobyte): 簡單、輕量、高度可移植,在手機平臺運行。運行速度慢
- JRockit: BEA--> Oracle,專註服務端應用,優勢:垃圾收集器+MissionControl服務套件
- J9( IBM Technology for Java Virtual Machine IT4j ): IBM公司開發,用於IBM的產品
- dalvik: Google公司設計,Android平臺核心組成部分之一
- Mircosoft JVM:
- Azul VM: 高性能,HotSpot 基礎上改進
- Liquid VM: 高性能,BEA公司開發,本身相當於一個操作系統
TaobaoVM: 根據OpenJDK深度定制
7.JVM內存管理
運行時數據區
1. 線程共享區
1.1. 方法區
- 保存類的元數據
- 元數據包括類型信息、常量池、域信息、方法信息
- 在HotSpot虛擬機中,方法區也被成為永久區
雖然叫做永久區,但是在永久區的對象也可以被GC回收
1.1.1 運行時常量池
- 方法區的一部分
用於存放編譯器生成的各種字面量和符號引用
1.2. Java堆
- 存放對象實例
- 垃圾收集器管理的主要區域
- 新生代、老年代
OutofMemoryError:內存溢出
2. 線程獨占區
2.1. Java虛擬機棧
- 描述的是Java方法執行的動態內存模型
- Java虛擬機棧主要被用來存放基本類型的變量,如:int、short、long、byte、float、double、boolea、char、對象引用
- StackoverflowError: 棧內存溢出,可以使用-XSS指定虛擬機棧的大小,棧的大小決定了函數調用的最大可達深度
虛擬機棧為虛擬機執行Java方法
2.2. 本地方法棧(Native Method Stacks)
本地方法棧用來執行Native方法
2.3. 程序計數器(Program Counter Register)
- 每一個線程都有一個獨立的程序計數器,用來記錄下一條需要執行的計算機指令
- 程序計數器是線程獨有的一塊內存空間。這塊內存是線程私有,生命周期與線程保持一致
- 如果當前線程正在執行一個Java方法,則程序計數器記錄正在執行的Java字節碼地址,如果當前線程正在執行一個本地方法,則程序計數器為空
唯一一個在Java虛擬機中內有規定任何OutofMemoryError情況的區域
8. 對象
8.1 對象的創建
1.給對象分配內存的方式
- 指針碰撞
空閑列表
2. 線程的安全性問題
- 線程同步(需要加鎖,效率低)
本地線程分配緩沖
3. 初始化對象
4. 執行構造方法
8.2對象的結構:
1. Header
1.自身運行時數據(Mark Word)
- 哈希值
- GC分代年齡
- 鎖狀態標識
- 線程持有的鎖
- 偏向線程ID
- 偏向時間戳
占用的空間:32位機器:32bit;64位機器:64bit
類型指針
2.InstanceData
3.Padding
8.3 對象的訪問定位
1.使用句柄
2.直接指針
9.垃圾回收
9.1 如何判斷對象為垃圾對象?
- 引用計數法
在對象中添加一個引用計數器,當有地方引用這個對象時計數器的值就+1,當引用失效時,計數器的值就-1
弊端:當對象循環引用時不能識別是否為垃圾對象
*基本沒有JVM在使用 - 可達性分析法
作為GCroot的對象- 虛擬機棧
- 方法區的類屬性所引用的對象
- 方法區中常量所引用的對象
- 本地方法棧中引用的對象
JDK8使用的垃圾回收器: parallel
9.2 回收算法
- 標記-清除算法
通過可達性分析法標記-->清楚
缺點:效率較低、空間問題(出現很多不連續的內存空間) - 復制算法
把使用中的內存復制一份重新按順序排列
缺點:內存只能用一半,不適用於老年代 - 標記-整理算法
讓所有存活的對象都向一端移動,然後清理掉邊界以外的內存 - 分代收集算法
堆
- 新生代
- Eden 伊甸園
- Survivor 存活區
- Tenured Gen
- 老年代
9.3 垃圾收集器
1. serial收集器
- 歷史最悠久
- 使用復制算法
- 單線程,垃圾收集時必須暫停其他所有的工作線程,直到收集結束
- 虛擬機運行在Client模式下的新生代收集器
- 用於桌面應用
2. ParNew收集器
- 多線程收集
- 虛擬機運行在Server模式下首選的新生代收集器
3. parallel Scavenge收集器
- 適用復制算法(新生代內存)
- 多線程收集器
- 達到可控制的吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間)
- -XX:MaxGCPauseMillis 垃圾收集器停頓時間
- -XX:GCTimeRatio 吞吐量大小 (0-100)
4. cms(Concurrent Mark Sweep)收集器
- 運作步驟
標記清除--並發標記--重新標記--並發清除 - 優點
- 並發收集
- 低停頓
- 缺點
- 占用大量的CPU資源
- 無法處理浮動垃圾
- 出現Concurrent Mode Failure
基於標記清除算法,會產生大料的空間碎片
5. G1(Garbage-First)收集器
面向服務端應用的垃圾收集器
優勢:
- 並行與並發, 使用多個CPU來縮短Stop-The-Word停頓時間
- 分代收集
- 空間整合:整體上看基於標記-整理算法,局部上看基於復制算法
- 可預測停頓
運作步驟:
- 初始標記
- 並發標記
- 最終標記
- 篩選回收 Remembered Set
10 . 內存分配
10.1 優先分配到Eden區
10.2 大對象直接進入老年代
10.3長期存活的對象進入老年代
10.4 空間分配擔保
10.5 動態對象的年齡判斷
11. JVM工具
https://docs.oracle.com/javase/8/docs/technotes/tools/index.html#monitor
11.1 jps (Java Process Status)
jenkins@ubuntu-OptiPlex-7040:~$ jps
13154 Bootstrap
12191 Jps
參數:
# -l :虛擬機執行主類名稱或者jar包的名稱
jenkins@ubuntu-OptiPlex-7040:~$ jps -l
13154 org.apache.catalina.startup.Bootstrap
12462 sun.tools.jps.Jps
# -m :主類接收的參數
jenkins@ubuntu-OptiPlex-7040:~$ jps -m
13154 Bootstrap start
12552 Jps -m
# -v :JVM接收的參數
jenkins@ubuntu-OptiPlex-7040:~$ jps -v
13154 Bootstrap -Djava.util.logging.config.file=/home/jenkins/tomcat/jenkins/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Dorg.apache.catalina.security.SecurityListener.UMASK=0027 -Dignore.endorsed.dirs= -Dcatalina.base=/home/jenkins/tomcat/jenkins -Dcatalina.home=/home/jenkins/tomcat/jenkins -Djava.io.tmpdir=/home/jenkins/tomcat/jenkins/temp
12675 Jps -Denv.class.path=.:/home/ubuntu/software/jdk/jdk1.8.0_151/lib:/home/ubuntu/software/jdk/jdk1.8.0_151/jre/lib -Dapplication.home=/home/ubuntu/software/jdk/jdk1.8.0_151 -Xms8m
11.2 jstat
虛擬機統計信息監控:類裝載、內存、垃圾收集、JIT編譯等運行數據
11.3 jinfo
實時查看和調整虛擬機各項參數
11.4 jmap
生產堆轉儲快照
$ jmap -dump:format=b,file=jenkins.bin 13154
Dumping heap to /home/jenkins/jenkins.bin ...
Heap dump file created
-XX:+HeapDumpOnOutofMemoryError : 虛擬機在OOM異常出現後自動生成dump文件
# 顯示堆中對象通信信息
$ jmap -histo 13154 | less
11.5 jhat
功能:分析jamp生成的堆轉儲快照
一般不會在生產服務器上進行分析,非常耗CPU和內存,不常用
jenkins@ubuntu-OptiPlex-7040:~$ jhat jenkins.bin
Reading from jenkins.bin...
Dump file created Thu Feb 14 11:43:45 CST 2019
Snapshot read, resolving...
Resolving 12022774 objects...
Chasing references, expect 2404
dots
Eliminating duplicate references
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.
瀏覽器訪問http://ip:7000 查看分析結果
11.7 jstack
功能: 生成虛擬機當前時刻的線程快照,用來定位線程出現長時間停頓的原因,如線程見死鎖、死循環、請求外部資源導致的長時間等待等
jstack -l 13154
11.8 jconsole
- 內存監控
- 線程監控
死鎖
11.9 jvisualvm
12. 性能調優
調優需要的技能:
- 知識
- 工具
- 數據
- 經驗
JVM虛擬機基礎知識