文章目錄
JVM發(fā)展史
一,歷代JDK新特性介紹
1996年 SUN JDK 1.0 Classic VM
1997年 JDK1.1 發(fā)布
1998年 JDK1.2 Solaris Exact VM
2000年 JDK 1.3 Hotspot 作為默認虛擬機發(fā)布
2002年 JDK 1.4 Classic VM退出歷史舞臺
2004年發(fā)布 JDK1.5 即 JDK5 、J2SE 5 、Java 5
2006年發(fā)布JDK1.6既JDK6
2011年 JDK7發(fā)布
2014年 JDK8發(fā)布
2016年JDK9
2018年JDK10
2018年JDK11
2019年JDK12
2019年JDK13
2020年發(fā)布JDK14
JVM運行機制
JVM模型
圖解:
PC寄存器
方法區(qū)
Java堆(新生代,老年代,持久代)
Matespace元數(shù)據(jù)區(qū)(jdk1.8新特性)
Java棧
棧、堆、方法區(qū)交互
JVM參數(shù)
1,堆設置
2,收集器設置
3,垃圾回收統(tǒng)計信息
4,并行收集器設置
5,并發(fā)收集器設置
參數(shù)介紹
參數(shù)設置(案例)
GC
引用計數(shù)
正向可達
串行收集器
并行收集器
GC參數(shù)整理
CMS運行過程比較復雜,著重實現(xiàn)了標記的過程,可分為
特點
ParNew
Parallel收集器
-XX:MaxGCPauseMills
-XX:GCTimeRatio
CMS收集器
GC的概念
GC參數(shù)
GC算法與種類
如何判斷對象是否可回收?
JVM監(jiān)控工具
JVM發(fā)展史
一,歷代JDK新特性介紹
1996年 SUN JDK 1.0 Classic VM
初代版本,偉大的一個里程碑,但是是純解釋運行,使用外掛JIT,性能比較差,運行速度慢。
1997年 JDK1.1 發(fā)布
AWT、內部類、JDBC、RMI、反射
1998年 JDK1.2 Solaris Exact VM
JIT 解釋器混合
Accurate Memory Management 精確內存管理,數(shù)據(jù)類型敏感
提升的GC性能
JDK1.2開始 稱為Java 2 J2SE J2EE J2ME 的出現(xiàn)
加入Swing Collections
2000年 JDK 1.3 Hotspot 作為默認虛擬機發(fā)布
加入JavaSound
2002年 JDK 1.4 Classic VM退出歷史舞臺
Assert 正則表達式 NIO IPV6 日志API 加密類庫
2004年發(fā)布 JDK1.5 即 JDK5 、J2SE 5 、Java 5
自動裝箱拆箱
泛型支持
元數(shù)據(jù)(注解)
Introspector(內省)
enum(枚舉)
靜態(tài)引入
可變長參數(shù)(Varargs)
foreach(高級虛幻)
JMM(內存模型)
concurrent(并發(fā)包)
2006年發(fā)布JDK1.6既JDK6
命名方式變更
腳本語言
編譯API和微型HTTP服務器API
鎖與同步
垃圾收集
類加載
JDBC 4.0(jdbc高級)
Java Compiler (Java? 編程語言編譯器的接口)
可插拔注解
Native PKI(公鑰基礎設)
Java GSS (通用安全服務)
Kerberos ( 一種安全認證的系統(tǒng))
LDAP (LDAP )
Web Services (web服務即xml傳輸)
2011年 JDK7發(fā)布
switch語句塊中允許以字符串作為分支條件
創(chuàng)建泛型對象時應用類型推斷
try-with-resources(一個語句塊中捕獲多種異常)
null值得自動處理
數(shù)值類型可以用二進制字符串表示
引入Java NIO.2開發(fā)包
動態(tài)語言支持
安全的加減乘除
Map集合支持并發(fā)請求
2014年 JDK8發(fā)布
引入Lambda 表達式
管道和流
新的日期和時間 API(加強對日期與時間的處理)
默認的方法(接口可以編寫默認的方法)
類型注解
Nashorn javascript引擎(允許java運行特定JavaScript代碼)
Optional class (處理nullPointException)
并行累加器
并行操作
內存錯誤移除
TLS SNI 服務器名稱標識(Server Name Identification)
2016年JDK9
模塊化
接口支持編寫私有方法
Javadoc改進(支持符合html5 標準輸出)
Stream API 增強(簡化調用、操作、提供常用便捷的方法)
image API增強(支持多分辨率解析)
多版本jar支持(在不同環(huán)境運行不同jar包)
改進棄用注解使用@Deprecated
內置輕量級json API
棄用Applet API
Deprecation的棄用
2018年JDK10
JEP286,var 局部變量類型推斷。
JEP296,將原來用 Mercurial 管理的眾多 JDK 倉庫代碼,合并到一個倉庫中,簡化開發(fā)和管理過程。
JEP304,統(tǒng)一的垃圾回收接口。
JEP307,G1 垃圾回收器的并行完整垃圾回收,實現(xiàn)并行性來改善最壞情況下的延遲。
JEP310,應用程序類數(shù)據(jù) (AppCDS) 共享,通過跨進程共享通用類元數(shù)據(jù)來減少內存占用空間,和減少啟動時間。
JEP312,ThreadLocal 握手交互。在不進入到全局 JVM 安全點 (Safepoint) 的情況下,對線程執(zhí)行回調。優(yōu)化可以只停止單個線程,而不是停全部線程或一個都不停。
JEP313,移除 JDK 中附帶的 javah 工具??梢允褂?javac -h 代替。
JEP314,使用附加的 Unicode 語言標記擴展。
JEP317,能將堆內存占用分配給用戶指定的備用內存設備。
JEP317,使用 Graal 基于 Java 的編譯器,可以預先把 Java 代碼編譯成本地代碼來提升效能。
JEP318,在 OpenJDK 中提供一組默認的根證書頒發(fā)機構證書。開源目前 Oracle 提供的的 Java SE 的根證書,這樣 OpenJDK 對開發(fā)人員使用起來更方便。
JEP322,基于時間定義的發(fā)布版本,即上述提到的發(fā)布周期。版本號為$FEATURE.$INTERIM.$UPDATE.$PATCH,分j別是大版本,中間版本,升級包和補丁版本。
2018年JDK11
新特性及更新修改:
基于嵌套的訪問控制
標準 HTTP Client 升級
Epsilon:低開銷垃圾回收器
簡化啟動單個源代碼文件的方法
用于 Lambda 參數(shù)的局部變量語法
低開銷的 Heap Profiling
支持 TLS 1.3 協(xié)議
ZGC:可伸縮低延遲垃圾收集器
飛行記錄器
動態(tài)類文件常量
2019年JDK12
Shenandoah: A Low-Pause-Time Garbage Collector (Experimental) 低暫停時間的GC
Microbenchmark Suite 微基準測試套件
Switch Expressions (Preview) Switch表達式
JVM Constants API JVM常量API
One AArch64 Port, Not Two 只保留一個AArch64實現(xiàn)
Default CDS Archives 默認類數(shù)據(jù)共享歸檔文件
Abortable Mixed Collections for G1 可中止的G1 Mixed GC
Promptly Return Unused Committed Memory from G1 G1及時返回未使用的已分配內存
2019年JDK13
JEP 350,Dynamic CDS Archives
擴展應用程序類-數(shù)據(jù)共享,以允許在 Java 應用程序執(zhí)行結束時動態(tài)歸檔類。歸檔類將包括默認的基礎層 CDS(class data-sharing)存檔中不存在的所有已加載的應用程序類和庫類。
JEP 351,ZGC: Uncommit Unused Memory
增強 ZGC 以將未使用的堆內存返回給操作系統(tǒng)。
JEP 353,Reimplement the Legacy Socket API
使用易于維護和調試的更簡單、更現(xiàn)代的實現(xiàn)替換 java.net.Socket 和java.net.ServerSocket API 使用的底層實現(xiàn)。
JEP 354,Switch Expressions (Preview)
可在生產環(huán)境中使用的 switch 表達式,JDK 13 中將帶來一個 beta 版本實現(xiàn)。switch 表達式擴展了 switch 語句,使其不僅可以作為語句(statement),還可以作為表達式(expression),并且兩種寫法都可以使用傳統(tǒng)的 switch 語法,或者使用簡化的“case L ->”模式匹配語法作用于不同范圍并控制執(zhí)行流。這些更改將簡化日常編碼工作,并為 switch 中的模式匹配(JEP 305)做好準備。
JEP 355,Text Blocks (Preview)
將文本塊添加到 Java 語言。文本塊是一個多行字符串文字,它避免了對大多數(shù)轉義序列的需要,以可預測的方式自動格式化字符串,并在需要時讓開發(fā)人員控制格式。
2020年發(fā)布JDK14
305:instanceof的模式匹配(預覽)
343:包裝工具(培養(yǎng)箱)
345:G1的NUMA感知內存分配
349:JFR事件流
352:非易失性映射字節(jié)緩沖區(qū)
358:有用的NullPointerExceptions
359:記錄(預覽)
361:開關表達式(標準)
362:棄用Solaris和SPARC端口
363:刪除并發(fā)標記掃描(CMS)垃圾收集器
364:Mac OS上的ZGC
365:Windows上的ZGC
366:棄用ParallelScavenge + SerialOld GC組合
367:刪除Pack200工具和API
368:文本塊(第二預覽)
370:外部存儲器訪問API(孵化器)
JVM運行機制
JVM模型
圖解:
PC寄存器
每個線程擁有一個PC寄存器
在線程創(chuàng)建時 創(chuàng)建
指向下一條指令的地址
執(zhí)行本地方法時,PC的值為undefined
方法區(qū)
保存裝載的類信息
類型的常量池
字段,方法信息
方法字節(jié)碼通常和永久區(qū)(Perm)關聯(lián)在一起
Java堆(新生代,老年代,持久代)
和程序開發(fā)密切相關
應用系統(tǒng)對象都保存在Java堆中
所有線程共享Java堆
對分代GC來說,堆也是分代的
GC的主要工作區(qū)間
Matespace元數(shù)據(jù)區(qū)(jdk1.8新特性)
從JDK8開始,永久代(PermGen)的概念被廢棄掉了,取而代之的是一個稱為Metaspace的存儲空間。Metaspace使用的是本地內存,而不是堆內存,也就是說在默認情況下Metaspace的大小只與本地內存大小有關。
-XX:MetaspaceSize=N
這個參數(shù)是初始化的Metaspace大小,該值越大觸發(fā)Metaspace GC的時機就越晚。隨著GC的到來,虛擬機會根據(jù)實際情況調控Metaspace的大小,可能增加上線也可能降低。在默認情況下,這個值大小根據(jù)不同的平臺在12M到20M浮動。使用java -XX:+PrintFlagsInitial命令查看本機的初始化參數(shù),-XX:Metaspacesize為21810376B(大約20.8M)。
-XX:MaxMetaspaceSize=N
這個參數(shù)用于限制Metaspace增長的上限,防止因為某些情況導致Metaspace無限的使用本地內存,影響到其他程序。在本機上該參數(shù)的默認值為4294967295B(大約4096MB)。
-XX:MinMetaspaceFreeRatio=N
當進行過Metaspace GC之后,會計算當前Metaspace的空閑空間比,如果空閑比小于這個參數(shù),那么虛擬機將增長Metaspace的大小。在本機該參數(shù)的默認值為40,也就是40%。設置該參數(shù)可以控制Metaspace的增長的速度,太小的值會導致Metaspace增長的緩慢,Metaspace的使用逐漸趨于飽和,可能會影響之后類的加載。而太大的值會導致Metaspace增長的過快,浪費內存。
-XX:MaxMetasaceFreeRatio=N
當進行過Metaspace GC之后, 會計算當前Metaspace的空閑空間比,如果空閑比大于這個參數(shù),那么虛擬機會釋放Metaspace的部分空間。在本機該參數(shù)的默認值為70,也就是70%。
-XX:MaxMetaspaceExpansion=N
Metaspace增長時的最大幅度。在本機上該參數(shù)的默認值為5452592B(大約為5MB)。
-XX:MinMetaspaceExpansion=N
Metaspace增長時的最小幅度。在本機上該參數(shù)的默認值為340784B(大約330KB為)。
Java棧
線程私有
棧由一系列幀組成(因此Java棧也叫做幀棧)
幀保存一個方法的局部變量、操作數(shù)棧、常量池指針
每一次方法調用創(chuàng)建一個幀,并壓棧
棧、堆、方法區(qū)交互
JVM參數(shù)
參數(shù)介紹
-Xss 設置每個線程可使用的內存大小,即棧的大小。
1,堆設置
-Xms 初始堆大小,默認為物理內存的1/64
-Xmx 最大堆大小,默認為物理內存的1/4
-Xmn 堆內新生代的大小。通過這個值也可以得到老生代的大?。?Xmx減去-Xmn
-XX:NewSize=n 設置年輕代大小
-XX:NewRatio=n 設置年輕代和年老代的比值。如:為3,表示年輕代與年老代比值為1:3,年輕代占整個年輕代年老代和的1/4
-XX:SurvivorRatio=n 年輕代中Eden區(qū)與兩個Survivor區(qū)的比值。注意Survivor區(qū)有兩個。如:3,表示Eden:Survivor=3:2,一個Survivor區(qū)占整個年輕代的1/5
-XX:MaxPermSize=n 設置持久代大小
-XX:MaxTenuringThreshold:設置轉入老年代的存活次數(shù)。如果是0,則直接跳過新生代進入老年代
-XX:PermSize、-XX:MaxPermSize:分別設置永久代最小大小與最大大小(Java8以前,8以后被Matespace元數(shù)據(jù)區(qū)替代)
2,收集器設置
-XX:+UseSerialGC 設置串行收集器
-XX:+UseParallelGC 設置并行收集器
-XX:+UseParalledlOldGC 設置并行年老代收集器
-XX:+UseConcMarkSweepGC 設置并發(fā)收集器
3,垃圾回收統(tǒng)計信息
-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:filename
4,并行收集器設置
-XX:ParallelGCThreads=n 設置并行收集器收集時使用的CPU數(shù)。并行收集線程數(shù)。
-XX:MaxGCPauseMillis=n 設置并行收集最大暫停時間
-XX:GCTimeRatio=n 設置垃圾回收時間占程序運行時間的百分比。公式為1/(1+n)
5,并發(fā)收集器設置
-XX:+CMSIncrementalMode 設置為增量模式。適用于單CPU情況。
-XX:ParallelGCThreads=n 設置并發(fā)收集器年輕代收集方式為并行收集時,使用的CPU數(shù)。并行收集線程數(shù)。
參數(shù)設置(案例)
GC
GC的概念
Garbage Collection 垃圾收集
1960年 List 使用了GC
Java中,GC的對象是堆空間和永久區(qū)
GC參數(shù)
串行收集器
最古老,最穩(wěn)定
效率高
可能會產生較長的停頓
-XX:+UseSerialGC
新生代、老年代使用串行回收
新生代復制算法
老年代標記-壓縮
并行收集器
ParNew
-XX:+UseParNewGC
新生代并行
老年代串行Serial收集器新生代的并行版本
復制算法
多線程,需要多核支持
-XX:ParallelGCThreads 限制線程數(shù)量
Parallel收集器
類似ParNew
新生代復制算法
老年代 標記-壓縮
更加關注吞吐量
-XX:+UseParallelGC
使用Parallel收集器 + 老年代串行-XX:+UseParallelOldGC
使用Parallel收集器 + 并行老年代
-XX:MaxGCPauseMills
最大停頓時間,單位毫秒
GC盡力保證回收時間不超過設定值
1
2
-XX:GCTimeRatio
0-100的取值范圍
垃圾收集時間占總時間的比
默認99,即最大允許1%時間做GC
這兩個參數(shù)是矛盾的。因為停頓時間和吞吐量不可能同時調優(yōu)
CMS收集器
Concurrent Mark Sweep 并發(fā)(與用戶線程一起執(zhí)行 )標記清除
標記-清除算法
與標記-壓縮相比
并發(fā)階段會降低吞吐量
老年代收集器(新生代使用ParNew)
-XX:+UseConcMarkSweepGC
-XX:+ UseCMSCompactAtFullCollection Full GC后,進行一次整理
整理過程是獨占的,會引起停頓時間變長
-XX:+CMSFullGCsBeforeCompaction
設置進行幾次Full GC后,進行一次碎片整理
-XX:ParallelCMSThreads
設定CMS的線程數(shù)量
CMS運行過程比較復雜,著重實現(xiàn)了標記的過程,可分為
初始標記
根可以直接關聯(lián)到的對象
速度快
并發(fā)標記(和用戶線程一起)
主要標記過程,標記全部對象重新標記
由于并發(fā)標記時,用戶線程依然運行,因此在正式清理前,再做修正
并發(fā)清除(和用戶線程一起)
基于標記結果,直接清理對象
特點
盡可能降低停頓
會影響系統(tǒng)整體吞吐量和性能
比如,在用戶線程運行過程中,分一半CPU去做GC,系統(tǒng)性能在GC階段,反應速度就下降一半
清理不徹底
因為在清理階段,用戶線程還在運行,會產生新的垃圾,無法清理
因為和用戶線程一起運行,不能在空間快滿時再清理
-XX:CMSInitiatingOccupancyFraction設置觸發(fā)GC的閾值
如果不幸內存預留空間不夠,就會引起concurrent mode failure
GC參數(shù)整理
-XX:+UseSerialGC:在新生代和老年代使用串行收集器
-XX:SurvivorRatio:設置eden區(qū)大小和survivior區(qū)大小的比例
-XX:NewRatio:新生代和老年代的比
-XX:+UseParNewGC:在新生代使用并行收集器
-XX:+UseParallelGC :新生代使用并行回收收集器
-XX:+UseParallelOldGC:老年代使用并行回收收集器
-XX:ParallelGCThreads:設置用于垃圾回收的線程數(shù)
-XX:+UseConcMarkSweepGC:新生代使用并行收集器,老年代使用CMS+串行收集器
-XX:ParallelCMSThreads:設定CMS的線程數(shù)量
-XX:CMSInitiatingOccupancyFraction:設置CMS收集器在老年代空間被使用多少后觸發(fā)
-XX:+UseSerialGC:在新生代和老年代使用串行收集器
-XX:SurvivorRatio:設置eden區(qū)大小和survivior區(qū)大小的比例
-XX:NewRatio:新生代和老年代的比
-XX:+UseParNewGC:在新生代使用并行收集器
-XX:+UseParallelGC :新生代使用并行回收收集器
-XX:+UseParallelOldGC:老年代使用并行回收收集器
-XX:ParallelGCThreads:設置用于垃圾回收的線程數(shù)
-XX:+UseConcMarkSweepGC:新生代使用并行收集器,老年代使用CMS+串行收集器
-XX:ParallelCMSThreads:設定CMS的線程數(shù)量
-XX:CMSInitiatingOccupancyFraction:設置CMS收集器在老年代空間被使用多少后觸發(fā)
GC算法與種類
新生代復制算法
老年代標記壓縮
標記清除
如何判斷對象是否可回收?
引用計數(shù)
引用計數(shù)算法是通過在對象頭中分配一個空間來保存該對象被引用的次數(shù)。如果該對象被其它對象引用,則它的引用計數(shù)加一,如果刪除對該對象的引用,那么它的引用計數(shù)就減一,當該對象的引用計數(shù)為0時,那么該對象就會被回收。
軟引用,弱引用,虛引用
正向可達
可觸及的
從根節(jié)點可以觸及到這個對象
可復活的
一旦所有引用被釋放,就是可復活狀態(tài)
因為在finalize()中可能復活該對象不可觸及的
在finalize()后,可能會進入不可觸及狀態(tài)
不可觸及的對象不可能復活
可以回收
JVM監(jiān)控工具
1.jdk自帶jconsole,jvisualvm (jdk的bin目錄)
2.Eclipse Memory Analyzer tool(MAT)
3.在線分析網址:https://fastthread.io
特別推薦一個分享架構+算法的優(yōu)質內容,還沒關注的小伙伴,可以長按關注一下:
長按訂閱更多精彩▼
如有收獲,點個在看,誠摯感謝
免責聲明:本文內容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!