本課時我們主要講解 JVM 的歷史與展望。
我們都知道,Java 目前被 Oracle 控制,它是從 Sun 公司手中收購的,HotSpot 最初也并非由 Sun 公司開發(fā),是由一家名為 Longview Technologies 的小公司設計的,而且這款虛擬機一開始也不是為 Java 語言開發(fā)的。
當時的 HotSpot,非常優(yōu)秀,尤其是在 JIT 編譯技術上,有一些超前的理念,于是 Sun 公司在 1997 年收購了 Longview Technologies,攬美人入懷。
Sun 公司是一家對技術非常專情的公司,他們對 Java 語言進行了發(fā)揚光大,尤其是在 JVM 上,做了一些非常大膽的嘗試和改進。
9 年后,Sun 公司在 2006 年的 JavaOne 大會上,將 Java 語言開源,并在 GPL 協(xié)議下公開源碼,在此基礎上建立了 OpenJDK。你應該聽說過,GPL 協(xié)議的限制,是比較寬松的,這極大的促進了 Java 的發(fā)展,同時推動了 JVM 的發(fā)展。
Sun 是一家非常有技術情懷的公司,最高市值曾超過 2000 億美元。但是,最后卻以 74 億美元的價格被 Oracle 收購了,讓人感嘆不已。
2010 年,HotSpot 進入了 Oracle 時代,這也是現(xiàn)在為什么要到 Oracle 官網上下載 J2SE 的原因。
幸運的是,我們有 OpenJDK 這個凝聚了眾多開源開發(fā)者心血的分支。從目前的情況來看,OpenJDK 與 Oracle 版本之間的差別越來越小,甚至一些超前的實驗性特性,也會在 OpenJDK 上進行開發(fā)。
對于我們使用者來說,這個差別并不大,因為 JVM 已經屏蔽了操作系統(tǒng)上的差異,而我們打交道的,是上層的 JRE 和 JDK。
其他虛擬機
由于 JVM 就是個規(guī)范,所以實現(xiàn)的方法也很多,完整的列表請點擊這里查看。
JVM 的版本非常之多,比較牛的公司都搞了自己的 JVM,但當時誰也沒想到,話語權竟會到了 Oracle 手里。下面舉幾個典型的例子。
J9 VM
我在早些年工作的時候,有錢的公司喜歡買大型機,比如會買 WebLogic、WebSphere 等服務器。對于你現(xiàn)在已經用慣了 Tomcat、Undertow 這些輕量級的 Web 服務器來說,這是一些很古老的名詞了。
WebSphere 就是這樣一個以“巨無霸”的形式存在,當年的中間件指的就是它,和現(xiàn)在的中間件完全不是一個概念。
WebSphere 是 IBM 的產品,開發(fā)語言是 Java。但是它運行時的 JVM,卻是一個叫做 J9 的虛擬機,依稀記得當年,有非常多的 jar 包,由于引用了一些非常偏門的 API,卻不能運行(現(xiàn)在應該好了很多)。
Zing VM
Zing JVM 是 Azul 公司傳統(tǒng)風格的產品,它在 HotSpot 上做了不少的定制及優(yōu)化,主打低延遲、高實時服務器端 JDK 市場。它代表了一類商業(yè)化的定制,比如 JRockit,都比較貴。
IKVM
這個以前在寫一些游戲的時候,使用過 LibGDX,相當于使用了 Java,最后卻能跑在 .net 環(huán)境上,使用的方式是 IKVM 。它包含了一個使用 .net 語言實現(xiàn)的 Java 虛擬機,配合 Mono 能夠完成 Java 和 .net 的交互,讓人認識到語言之間的鴻溝是那么的渺小。
Dalvik
Android 的 JVM,就是讓 Google 吃官司的那個,從現(xiàn)在 Android 的流行度上也能看出來,Dalvik 優(yōu)化的很好。
歷史
下面我簡單講講 Java 的發(fā)展歷史:
1995 年 5 月 23 日,Sun 公司正式發(fā)布了 Java 語言和 HotJava 瀏覽器;
1996 年 1 月,Sun 公司發(fā)布了 Java 的第一個開發(fā)工具包(JDK 1.0);
1996 年 4 月,10 個最主要的操作系統(tǒng)供應商申明將在其產品中嵌入 Java 技術,發(fā)展可真是迅雷不及掩耳;
1996 年 9 月,約 8.3 萬個網頁應用了 Java 技術來制作,這就是早年的互聯(lián)網,即 Java Applet,真香;
1996 年 10 月,Sun 公司發(fā)布了 Java 平臺第一個即時編譯器(JIT),這一年很不平凡;
1997 年 2 月 18 日,JDK 1.1 面世,在隨后的三周時間里,達到了 22 萬次的下載量,PHP 甘拜下風;
1999 年 6 月,Sun 公司發(fā)布了第二代 Java 三大版本,即 J2SE、J2ME、J2EE,隨之 Java2 版本發(fā)布;
2000 年 5 月 8 日,JDK 1.3 發(fā)布,四年升三版,不算過分哈;
2000 年 5 月 29 日,JDK 1.4 發(fā)布,獲得 Apple 公司 Mac OS 的工業(yè)標準支持;
2001 年 9 月 24 日,Java EE 1.3 發(fā)布,注意是 EE,從此開始臃腫無比;
2002 年 2 月 26 日,J2SE 1.4 發(fā)布,自此 Java 的計算能力有了大幅度的提升,與 J2SE 1.3 相比,多了近 62% 的類與接口;
2004 年 9 月 30 日 18:00PM,J2SE 1.5 發(fā)布,1.5 正式更名為 Java SE 5.0;
2005 年 6 月,在 JavaOne 大會上,Sun 公司發(fā)布了 Java SE 6;
2009 年 4 月 20 日,Oracle 宣布收購 Sun,該交易的總價值約為 74 億美元;
2010 年 Java 編程語言的創(chuàng)始人 James Gosling 從 Oracle 公司辭職,一朝天子一朝臣,國外也不例外;
2011 年 7 月 28 日,Oracle 公司終于發(fā)布了 Java 7,這次版本升級經過了將近 5 年時間;
2014 年 3 月 18 日,Oracle 公司發(fā)布了 Java 8,這次版本升級為 Java 帶來了全新的 Lambda 表達式。
小碎步越來越快,擔心很快 2 位數(shù)都裝不下 Java 的版本號了。目前 Java 的版本已經更新到 14 了,但市場主流使用的還是 JDK 8 版本。
最近更新
有些我們現(xiàn)在認為理所當然的功能,在 Java 的早期版本是沒有的。我們從 Java 7 說起,以下內容僅供參考,詳細列表見 openjdk JEP 列表。
Java 7
Java 7 增加了以下新特性:
try、catch 能夠捕獲多個異常
新增 try-with-resources 語法
JSR341 腳本語言新規(guī)范
JSR203 更多的 NIO 相關函數(shù)
JSR292,第 17 課時提到的 InvokeDynamic
支持 JDBC 4.1 規(guī)范
文件操作的 Path 接口、DirectoryStream、Files、WatchService
jcmd 命令
多線程 fork/join 框架
Java Mission Control
Java 8
Java 8 也是一個重要的版本,在語法層面上有更大的改動,支持 Lamda 表達式,影響堪比 Java 5 的泛型支持:
支持 Lamda 表達式
支持集合的 stream 操作
提升了 HashMaps 的性能(紅黑樹)
提供了一系列線程安全的日期處理類
完全去掉了 Perm 區(qū)
Java 9
Java 9 增加了以下新特性:
JSR376 Java 平臺模塊系統(tǒng)
JEP261 模塊系統(tǒng)
jlink 精簡 JDK 大小
G1 成為默認垃圾回收器
CMS 垃圾回收器進入廢棄倒計時
GC Log 參數(shù)完全改變,且不兼容
JEP110 支持 HTTP2,同時改進 HttpClient 的 API,支持異步模式
jshell 支持類似于 Python 的交互式模式
Java 10
Java 10 增加了以下新特性:
JEP304 垃圾回收器接口代碼進行整改
JEP307 G1 在 FullGC 時采用并行收集方式
JEP313 移除 javah 命令
JEP317 重磅 JIT 編譯器 Graal 進入實驗階段
Java 11
Java 11 增加了以下新特性:
JEP318 引入了 Epsilon 垃圾回收器,這個回收器什么都不干,適合短期任務
JEP320 移除了 JavaEE 和 CORBA Modules,應該要走輕量級路線
Flight Recorder 功能,類似 JMC 工具里的功能
JEP321 內置 httpclient 功能,java.net.http 包
JEP323 允許 lambda 表達式使用 var 變量
廢棄了 -XX+AggressiveOpts 選項
引入了 ZGC,依然是實驗性質
Java 12
Java 12 增加了以下新特性:
JEP189 先加入 ShenandoahGC
JEP325 switch 可以使用表達式
JEP344 優(yōu)化 G1 達成預定目標
優(yōu)化 ZGC
Java 13
Java 13 增加了以下新特性:
JEP354 yield 替代 break
JEP355 加入了 Text Blocks,類似 Python 的多行文本
ZGC 的最大 heap 大小增大到 16TB
廢棄 rmic Tool 并準備移除
Java 14
Java 14 增加了以下新特性:
JEP343 打包工具引入
JEP345 實現(xiàn)了 NUMA-aware 的內存分配,以提升 G1 在大型機器上的性能
JEP359 引入了 preview 版本的 record 類型,可用于替換 lombok 的部分功能
JEP364 之前的 ZGC 只能在 Linux 上使用,現(xiàn)在 Mac 和 Windows 上也能使用 ZGC 了
JEP363 正式移除 CMS,我們課程里提到的一些優(yōu)化參數(shù),在 14 版本普及之后,將不復存在
OpenJDK 64-Bit Server VM warning: Ignoring option UseConcMarkSweepGC; support was removed in 14.0
現(xiàn)狀
先看一下 2019 年 JVM 生態(tài)系統(tǒng)報告部分圖示,部分圖示參考了 snyk 這個網站。
生產環(huán)境中,主要用哪些 JDK
可以看到 OracleJDK 和 OpenJDK 幾乎統(tǒng)治了江湖,如果沒有 IBM 那些捆綁銷售的產品,份額只會更高。另外,使用 OpenJDK 的越來越多,差異也越來越小,在公有云、私有云等方面的競爭格局,深刻影響著在 OpenJDK 上的競爭格局;OpenJDK 很有可能被認為是一種退?求其次的選擇。
生產環(huán)境中,用哪個版本的 Java
以 8 版本為主,當然還有 6 版本以下的,嘗鮮的并不是很多,因為服務器環(huán)境的穩(wěn)定性最重要。新版本升級在中國的宣傳還是不夠,如果很多企業(yè)看不到技術升級的紅利,勢必也會影響升級的積極性。
應用程序的主要 JVM 語言是什么
很多人反應 Kotlin 非常好用,我嘗試著推廣了一下,被喜歡 Groovy 的朋友鄙視了一番,目前還是以 Java 居多。
展望
有點規(guī)模的互聯(lián)網公司,行事都會有些謹慎,雖然 JVM 做到了向下版本的兼容,但是有些性能問題還是不容忽視,嘗鮮吃螃蟹的并不是很多。
現(xiàn)在用的最多的,就是 Java 8 版本。如果你的服務器用的這個,那么用的最多的垃圾回收器就是 CMS,或者 G1。隨著 ZGC 越來越穩(wěn)定,CMS 終將會成為過去式。
目前,最先進的垃圾回收器,叫做 ZGC,它有 3 個 flag:
支持 TB 級堆內存(最大 4T)
最大 GC 停頓 10ms
對吞吐量影響最大,不超過 15%
每一個版本的發(fā)布,Java 都會對以下進行改進:
優(yōu)化垃圾回收器,減少停頓,提高吞吐
語言語法層面的升級,這部分在最近的版本里最為明顯
結構調整,減少運行環(huán)境的大小,模塊化
廢棄掉一些承諾要廢棄的模塊
那么 JVM 將向何處發(fā)展呢?以目前來看,比較先進的技術,就是剛才提到的垃圾回收階段的 ZGC ,能夠顯著的減少 STW 的問題;另外, GraalVM 是 Oracle 創(chuàng)建的一個研究項目,目標是完全替換 HotSpot,它是一個高性能的 JIT 編譯器,接受 JVM 字節(jié)碼,并生成機器代碼。未來,會有更多的開發(fā)語言運行在 JVM 上,比如 Python、Ruby 等。
Poject Loom 致力于在 JVM 層面,給予 Java 協(xié)程 (fibers)的功能,Java 程序的并發(fā)性能會上一個檔次。
Java 版本大部分是向下兼容的,能夠做到這個兼容,是非常不容易的。但 Java 的特性越加越多,如果開發(fā)人員不能進行平滑的升級,會是一個非常嚴重的問題,JVM 也將會在這里花費非常大的精力。
那 JVM 將聚焦在哪些方面呢?又有哪些挑戰(zhàn)?我大體總結了幾點:
內存管理依然是非常大的挑戰(zhàn),未來會有更厲害的垃圾回收器來支持更大的堆空間
多線程和協(xié)程,未來會加大對多核的利用,以及對輕量級線程的支持
性能,增加整個 JVM 的執(zhí)行效率,這通常是多個模塊協(xié)作的結果
對象管理和追蹤,復雜的對象,有著復雜的生命周期,加上難以預料的內存申請方式,需要更精準的管理優(yōu)化
可預測性及易用性,更少的優(yōu)化參數(shù),更高的性能
更多 JVM 監(jiān)控工具,提供對 JVM 全方面的監(jiān)控,跟蹤對象,在線優(yōu)化
多語言支持,支持除了 Java 語言之外的其他開發(fā)語言,能夠運行在 JVM 上
總結
Java 9 之后,已經進入了快速發(fā)布階段,大約每半年發(fā)布一次,Java 8 和 Java 11 是目前支持的 LTS 版本,它的功能變動也越來越多、越來越快。讓我們把握好 Java 發(fā)展的脈搏,一起加油吧。