淺談JVM整體架構與調優參數

本文分享自華爲雲社區《【性能優化】JVM整體架構與調優參數說明》,作者: 冰 河。

JVM的分類

這裏,我們先來說說什麼是VM吧,VM的中文含義爲:虛擬機,指的是使用軟件的方式模擬具有完整硬件系統功能、運行在一個完全隔離環境中的完整計算機系統,是物理機的軟件實現。

常用的虛擬機有:VMWare、Virtual Box,Java Virtual Machine(JVM,Java虛擬機)。

這裏,我們重點聊的就是JVM,Java虛擬機。看下圖。

825b2eec70954776a8fe95791340256c.png

這張圖看起來還是比較簡單的,JVM運行於操作系統之上,操作系統是運行在計算機硬件上的。

關於JVM,其實有很多大廠開發了不同版本的JVM,比較知名的有:Sun HotSpot VM、BEA JRockit VM、IBM J9 VM、 Azul VM、 Apache Harmony、 Google Dalvik VM、 Microsoft JVM等等。

現在使用的比較多的JDK8版本就是Sun HotSpot VM與BEA JRockit VM合併之後開發出的JDK版本。

JVM的構成

JVM主要由三個子系統構成,分別爲:類加載器子系統、運行時數據區(內存結構)和字節碼執行引擎

fa4b9d489ffb407ba6e9ffaf9b4ed420.png

爲了更好的理解JVM,我們來看一下JVM的全貌圖。

06afe983572e4c529d6b49c5b57f055f.png

當我們開發Java程序時,首先會編寫.java文件,之後,會將.java文件編譯成.class文件。

JVM中,會通過類裝載子系統將.class文件的內容裝載到JVM的運行時數據區,而JVM的運行時數據區又會分爲:方法區、堆、棧、本地方法棧和程序計數器 幾個部分。

在裝載class文件的內容時,會將class文件的內容拆分爲幾個部分,分別裝載到JVM運行時數據區的幾個部分。其中,值得注意的是:程序計數器的作用是:記錄程序執行的下一條指令的地址。

方法區也叫作元空間,主要包含了:運行時常量池、類型信息、字段信息、方法信息、類加載器的引用、對應的Class實例的引用等信息。

在JVM中,程序的執行是通過執行引擎進行的,執行引擎會調用本地方法的接口來執行本地方法庫,進而完成整個程序邏輯的執行。

我們常說的垃圾收集器是包含在執行引擎中的,在程序的運行過程中,執行引擎會開啓垃圾收集器,並在後臺運行,垃圾收集器會不斷監控程序運行過程中產生的內存垃圾信息,並根據相應的策略對垃圾信息進行清理。

這裏,大家需要注意的是:棧、本地方法棧和程序計數器是每個線程運行時獨佔的,而方法區和堆是所有線程共享的。所以,棧、本地方法棧和程序計數器不會涉及線程安全問題,而方法區和堆會涉及線程安全問題。

方法區(元空間)

很多小夥伴一看到方法區三個字,腦海中的第一印象可能是存儲方法的地方吧。

實則不然,方法區的另一個名字叫作元空間,相信不少小夥伴或多或少的聽說過元空間。這個區域是JDK1.8中劃分出來的。主要包含:運行時常量池、類型信息、字段信息、方法信息、類加載器的引用、對應的Class實例的引用等信息。方法區中的信息能夠被多個線程共享。

例如,在程序中聲明的常量、靜態變量和有關於類的信息等的引用,都會存放在方法區,而這些引用所指向的具體對象 一般都會在堆中開闢單獨的空間進行存儲,也可能會在直接內存中進行存儲

622d2f8cbaf5494a8f00c10756eeeb4a.png

堆中主要存儲的是實際創建的對象,也就是會存儲通過new關鍵字創建的對象,堆中的對象能夠被多個線程共享。堆中的數據不需要事先明確生存期,可以動態的分配內存,不再使用的數據和對象由JVM中的GC機制自動回收。對JVM的性能調優一般就是對堆內存的調優

Java中基本類型的包裝類:Byte、Short、Integer、Long、Float、Double、Boolean、Character類型的數據是存儲在堆中的。

堆一般會被分成年輕代和老年代。而年輕代又會被進一步分爲1個Eden區和2個Survivor區。在內存分配上,如果保持默認配置的話,年輕代和老年代的內存大小比例爲1 : 2,年輕代中的1個Eden區和2個Survivor區的內存大小比例爲:8 : 1 : 1。

3412dfc8c91049e2a0837b78e0cf5db2.png

棧一般又叫作線程棧或虛擬機棧,一般存儲的是局部變量。在Java中,每個線程都會有一個單獨的棧區,每個棧中的元素都是私有的,不會被其他的棧所訪問。棧中的數據大小和生存期都是確定的,存取速度比較快。

在Java中,所有的基本數據類型(byte、short、int、long、float、double、boolean、char)和引用變量(對象引用)都是在棧中的。一般情況下,線程退出或者方法退出時,棧中的數據會被自動清除

程序在執行過程中,會在棧中爲不同的方法創建不同的棧幀,在棧幀中又包含了:局部變量表、操作數棧、動態鏈接和方法出口。

e2e7eae6e0d5405ca6647c6ca5777162.png

關於局部變量表、操作數棧、動態鏈接和方法出口的具體作用,會在《架構師進階系列》中的後續文章中詳細闡述。

棧中一般會存儲對象的引用,這些引用所指向的具體對象一般都會在堆中開闢單獨的地址空間進行存儲,也有可能存儲在直接內存中。

3fadd1a139fd40978e76284614d84575.png

注意: 這裏說的是這些引用所指向的具體對象一般都會在堆中開闢單獨的地址空間進行存儲,也有可能存儲在直接內存中。

因爲在JVM中,如果開啓了逃逸分析和標量替換,則可能不會再在堆上創建對象,可能會將對象直接分配到棧上,也可能不再創建對象,而是進一步分解對象中的成員變量,將其直接在棧上分配空間並賦值。

本地方法棧

本地方法棧相對來說比較簡單,就是保存native方法進入區域的地址。

例如,在Java中創建線程,調用Thread對象的start()方法時,會通過本地方法start0()調用操作系統創建線程的方法。此時,本地方法棧就會保存start0()方法進入區域的內存地址。

程序計數器

程序計數器也叫作PC計數器,只要存儲的是下一條將要執行的命令的地址。

JVM調優參數

在JVM中,主要是對堆(新生代)、方法區和棧進行性能調優。各個區域的調優參數如下所示。

  • 堆:-Xms、-Xmx
  • 新生代:-Xmn
  • 方法區(元空間):-XX:MetaspaceSize、-XX:MaxMetaspaceSize
  • 棧(線程):-Xss

爲了更加直觀的表述,我們可以將JVM的內存區域和對應的調優參數總結成下圖所示。

d2e8e09e945d434da6dfc9de1a6043b1.png

在設置JVM啓動參數時,需要特別注意方法區(元空間)的參數設置。

關於方法區(元空間)的JVM參數主要有兩個:-XX:MetaspaceSize和-XX:MaxMetaspaceSize。

-XX:MetaspaceSize: 指的是方法區(元空間)觸發Full GC的初始內存大小(方法區沒有固定的初始內存大小),以字節爲單位,默認爲21M。達到設置的值時,會觸發Full GC,同時垃圾收集器會對這個值進行修改。

如果在發生Full GC時,回收了大量內存空間,則垃圾收集器會適當降低此值的大小;如果在發生Full GC時,釋放的空間比較少,則在不超過設置的-XX:MetaspaceSize值或者在沒設置-XX:MetaspaceSize的值時不超過21M,適當提高此值。

-XX:MaxMetaspaceSize: 指的是方法區(元空間)的最大值,默認值爲-1,不受堆內存大小限制,此時,只會受限於本地內存大小。

最後需要注意的是: 調整方法區(元空間)的大小會發生Full GC,這種操作的代價是非常昂貴的。如果發現應用在啓動的時候發生了Full GC,則很有可能是方法區(元空間)的大小被動態調整了。

所以,爲了儘量不讓JVM動態調整方法區(元空間)的大小造成頻繁的Full GC,一般將-XX:MetaspaceSize和-XX:MaxMetaspaceSize設置成一樣的值。例如,物理內存8G,可以將這兩個值設置爲256M

最後,我們一起看下在物理內存8G的情況下,啓動應用程序時,可以設置的JVM參數。當然,我這裏給出的是一些經驗值,實際部署到生產環境時,需要經過壓測找到最佳的參數值。

  • 啓動SpringBoot
java ‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐jar xxx.jar
  • 啓動Tomcat(Linux)

在Tomcat bin目錄下catalina.sh文件裏配置。

‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M
  • 啓動Tomcat(Windows)

在Tomcat bin目錄下catalina.bat文件裏配置。

‐Xms2048M ‐Xmx2048M ‐Xmn1024M ‐Xss512K ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M

總結

今天,我們一起學習了JVM的整體架構和調優參數,主要包括:JVM的總體結構、JVM的分類、JVM的構成和調優參數。你學會了嗎?歡迎在文末留言說出你的想法,如果你有更好的見解,也可以在文末留言和大家交流。

點擊關注,第一時間瞭解華爲雲新鮮技術~

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章