溪源的Java筆記—JVM
前言
作為一個Java
開發,JVM
是我們必須要了解的,我們只有建立在瞭解它的基本運作原理,才可能設計出一個最合理的程式碼方案,在此之前我們已經瞭解了集合中的Map
介面,接下來溪源我將帶領大家瞭解一下JVM
,希望對大家略有幫助。
集合之Map介面可參考我的部落格:溪源的Java筆記—集合之Map介面
正文
JVM
JVM為了達到給所有硬體提供一致的虛擬平臺的目的,犧牲了一些與硬體相關的特性。
Java
原始檔可以通過編譯器轉化成位元組碼檔案(.class
檔案),這些位元組碼檔案又可以被JVM
轉化成機器碼。JVM
是執行在作業系統之上的,它與硬體沒有直接互動。Java
的執行緒和原生作業系統執行緒有對映關係,Java
可以通過對應的作業系統執行緒來獲取計算機資源。
執行緒共享的資料區:
- 方法區:儲存程式執行時長期存活的物件,比如類的後設資料( 後設資料生成相應的
java
檔案)、方法、屬性等 (常量在JDK1.8移至JVM
堆中) - JVM堆:存放物件、陣列、常量等,垃圾收集器就是收集這些物件,然後根據
GC
演算法回收。
知識點:
- 在JDK1.8中廢棄了永久代區域,方法區被放在了元空間,這種設計可以避免永久代
OOM
(記憶體溢位)導致觸發GC
。元空間並不在虛擬機器中,而是使用本地記憶體。因此,預設情況下,元空間的大小僅受本地記憶體限制。預設在20M左右,放在元空間的永久代滿了即,達到MetaspaceSize
的閾值,同樣也會觸發FullGC
. - 常量在JDK1.8由方法區移至
JVM
堆中。 - 類的後設資料即類的描述資料,虛擬機器通過後設資料可以生成對應的物件。
執行緒隔離的資料區:
- 本地方法棧:
Natitve
方法 - 虛擬機器棧(JVM方法棧):區域性變數區、運算元棧、動態連線(方法呼叫過程的動態連線)、方法返回地址(可以理解為一個類方法的執行區域)。
- 程式計數暫存器(PC暫存器): 用於記錄正在執行的虛擬機器位元組序列的行指示器。
知識點:
- 每一個執行緒都會生成
PC
暫存器和虛擬機器棧。 - 棧的棧由系統自動分配,而堆,需要程式設計師自己申請並指明大小
JVM堆的組成
1/3的新生代:(由 Minor GC進行清理,採用複製演算法)
- GC開始前,物件只會存在於
Eden
區和名為“From”
的Survivor
區,Survivor
區“To”
是空的。 - GC中,
Eden
區中所有存活的物件都會被複制到“To”
,而在“From”
區中,仍存活的物件會根據他們的年齡值來決定去向。 - GC結束後,
Eden
區和From
區已經被清空,這個“To”
和“From”
互換角色,此時Survivor
區“To”
是空的,而“From”
保留上次GC
存活物件
整個流程可以概括 複製-清空-互換。
2/3的老年代:( 由Major GC進行清理,採用標記清除演算法 )
- 用於存放新生代中經過多次垃圾回收仍然存活的物件
- 新生代分配不了記憶體的大物件會直接進入老年代
知識點:
- 新生代滿了,會放至到空閒的
Survivor
區,只有所有的Survivor
區滿了才會放到老年代。 Survivor
區的作用是減少被送到老年代的物件,進而減少Full GC
的發生,Survivor
的預篩選保證,只有經歷16次Minor GC
還能在新生代中存活的物件,才會被送到老年代。
JVM回收機制
JVM確認垃圾回收物件的方式
- 引用計數法:當引用數為0時,物件死亡
- 根搜尋演算法:根物件(
GC ROOTS
)到某物件不可達時,物件死亡。
GC ROOTS的物件包括:
- 虛擬機器棧中的引用物件
- 本地方法棧的引用物件
- 方法區中靜態屬性引用的物件
- 方法區中靜態常量池中引用的物件
JVM垃圾回收演算法
- 標記-清除演算法:效率偏低
- 複製演算法:效率高,但是佔用2倍記憶體 (預留一塊記憶體 將還存活的物件放到該記憶體)
- 標記-整理演算法:效率偏低(是對標記-清除演算法的改進,讓存活的物件向一段移動)
- 分代收集演算法:把
Java
堆分為新生代和老年代,根據年代將特徵選擇上述演算法。新生代通常採用複製演算法,老年代採用標記-清除演算法或者標記-整理演算法。
常見的GC方式
- Minor GC:是清理新生代
- MajorGC:是指清理老年代
- Full GC:清理新生代和老年代
GC
,通常來時Full GC
比Minor GC
至少慢10倍。
觸發Full GC的情況 :
- 老年代滿了
- 永久代滿了
System.gc()
- 採用
CMS
收集器發生"Concurrent Mode Failure”
異常時
知識點:
- 立即回收還是延遲迴收是取決於
JVM
的,所以即使有GC
機制還是可能存在無用但可達的物件沒有即時被回收而導致記憶體洩漏。
垃圾收集器
垃圾收集器,又稱為垃圾回收器,是垃圾回收演算法(標記-清除演算法、複製演算法、標記-整理演算法)的具體實現,不同版本的JVM
所提供的垃圾收集器可能會有很在差別,本文主要介紹HotSpot
虛擬機器中的垃圾收集器。
選擇垃圾回收器考慮的因素:
- 應用程式的場景
- 硬體的制約
- 吞吐量的需求
選擇垃圾回收器的標準:
- 發生gc的停頓時間
- 產生空間碎片的大小,會間接影響併發量
序列、並行和併發的區別:
- 序列: 只會使用一個
CPU
或一條收集執行緒去完成垃圾收集工作 ,並且在進行垃圾收集時,必須暫停其他所有的工作執行緒。 - 並行:指多條垃圾收集執行緒並行工作,但此時使用者執行緒仍然處於等待狀態;
- 併發:指使用者執行緒與垃圾收集執行緒同時執行(但不一定是並行的,可能會交替執行);使用者程式在繼續執行,而垃圾收集程式執行緒執行於另一個
CPU
上;
常見的收集器(7種)
- 新生代收集器:
Serial
、ParNew
、Parallel Scavenge
(複製演算法) - 老年代收集器:
Serial Old
、Parallel Old
、CMS
; (1、2 採用標記整理演算法 3採用標記清除演算法) - 整堆收集器:
G1
;(標記整理,分割槽)
ParNew收集器
ParNew
的特點:
- 用於新生代收集器
- 採用複製演算法
- 並行,採用多執行緒收集,垃圾手機時會造成
“Stop The World”
應用場景:在多核的情況下和CMS
搭配使用,以滿足使用者互動頻繁實現低延遲的場景(最常見就是遊戲)
Parallel Scavenge收集器
Parallel Scavenge
的特點:
- 用於新生代收集器
- 採用複製演算法
- 並行,採用多執行緒收集,垃圾收集時會造成
“Stop The World”
Parallel Scavenge
沒有采用傳統的GC
程式碼框架,它相對於ParNew
的特點在於:JVM
會根據當前系統執行情況收集效能監控資訊,動態調整這些引數,以提供最合適的停頓時間或最大的吞吐量,這種調節方式稱為GC
自適應的調節策略
應用的場景:在多核的情況下和Parallel Old
搭配使用,以滿足高併發的場景(預設的搭配,最常就是web應用)
Parallel Old收集器
Parallel Old
的特點:
- 用於老年代收集器
- 採用”標記—整理"演算法
- 並行,採用多執行緒收集,垃圾收集時會造成
“Stop The World”
應用的場景:在多核的情況下和Parallel Scavenge
搭配使用,以滿足高併發的場景(預設的搭配,最常就是web
應用)
CMS收集器
CMS
的特點:
- 基於"標記-清除”演算法,不進行壓縮,以產生記憶體碎片,換取更短回收停頓時間
- 併發收集、低停頓
- 需要更多記憶體
應用的場景:在多核的情況下和Parallel Scavenge
搭配使用,以滿足使用者互動頻繁實現低延遲的場景(最常見就是遊戲)
CMS
運作的過程:
- 初始標記:僅標記
GC Roots
能直接關聯到的物件,速度很快,但會造成“Stop The World”
- 併發標記:應用程式執行的同時,對初始標記的物件中存活的物件進行標記,並不能保證可以標記出所有的存活物件;
- 重新標記:為了修正併發標記期間因使用者程式繼續運作而導致標記變動的那一部分物件的標記記錄,會造成
“Stop The World”
,停頓時間比初始標記稍長,但遠比並發標記短; - 併發清除:應用程式執行的同時,回收所有的垃圾物件
CMS
的缺陷:
- 對
CPU
資源非常敏感:當CPU
核數低於4時,效能會比較差 - 在併發清除時無法處理應用程式新產生的垃圾物件(即浮動垃圾),所以需要此時需要預留一定的記憶體空間,當預留的空間也無法填滿時會出現
"Concurrent Mode Failure”
失敗,JVM
會臨時啟用Serail Old
收集器,而導致另一次Full GC
的產生; - 由於採用"標記-清除”演算法,會產生大量的記憶體碎片。
G1收集器
G1
的特點:
- 並行與併發:既可以並行來縮短
"Stop The World”
停頓時間,也可以併發讓垃圾收集與使用者程式同時進行,減少停頓時間; - 分代收集:將整個堆劃分為多個大小相等的獨立區域 (
Region
),能夠採用不同方式處理不同時期的物件; - 結合多種垃圾收集演算法,空間整合,不產生碎片: 從整體看,是基於標記-整理演算法;從區域性(兩個
Region
間)看,是基於複製演算法; - 可預測的停頓:低停頓的同時實現高吞吐量
應用場景:具有比較大的記憶體空間、物件相對比較大的場景。
G1
的運作流程:
- 初始標記:僅標記
GC Roots
能直接關聯到的物件,並且修改TAMS
(Next Top at Mark Start
),讓下一階段併發執行時,使用者程式能在正確可用的Region
中建立新物件,速度很快,但會造成“Stop The World”
。 - 併發標記:應用程式執行的同時,對初始標記的物件中存活的物件進行標記,同時物件的變化記錄線上程的
Remembered Set Log
,並不能保證可以標記出所有的存活物件; - 最終標記 :為了修正併發標記期間因使用者程式繼續運作而導致標記變動的那一部分物件的標記記錄,這裡把
Remembered Set Log
合併到Remembered Set
中; 會造成“Stop The World”
,停頓時間比初始標記稍長,但遠比並發標記短; - 篩選回收:首先排序各個
Region
的回收價值和成本,然後根據使用者期望的GC
停頓時間來制定回收計劃;,最後按計劃回收一些價值高的Region
中垃圾物件;採用複製演算法和並行的方式,降低停頓時間、並增加併發量。
Java四種引用型別
- 強引用:
A a=new A()
只要引用a存在,垃圾回收器不會回收。 - 軟引用:
SoftReference
類似於快取的方式,不影響垃圾回收,可以提升速度,節省記憶體。若物件被回收,此時可以重新new
,主要是用來快取伺服器中間計算結果以及不需要實時儲存的使用者行為。通常放在用在對快取比較敏感的應用中。 - 弱引用:
WeakReference
用於監控物件是否被垃圾回收器回收。 - 虛引用:
PhantomReference
,每次垃圾回收的時候都會被回收。主要用於判斷物件是否已經從記憶體中刪除。
類載入機制
類載入器的任務就是.class
檔案載入到到JVM
轉換成 java.lang.class
類
常見的類載入器
- 根類載入器:用來載入
Java
的核心類; - 擴充套件類載入器:用來載入
jre
的擴充套件目錄; - 系統載入器:它負責在
JVM
啟動時載入來自Java
命令的-classpath
選項、java.class.path
系統屬性,或者CLASSPATH
換將變數所指定的JAR
包和類路徑。
雙親委託模型
雙親委託模型,確保了載入的唯一性,當類收到載入請求時,它首先不會嘗試載入這個類,而是把請求委託給父類載入器執行,每個類都是如此(如果還有父類繼續上交),只有父類載入完或者父類不存在,子類才會進行載入。
類載入過程
裝載:獲取類的二進位制位元組流,將其靜態儲存結構轉化為方法區的執行時資料結構;
連結,可以細分為:
- 校驗:獲取類的二進位制位元組流,將其靜態儲存結構轉化為方法區的執行時資料結構;
- 準備:在方法區中對類的
static
變數分配記憶體並設定類變數資料型別預設的初始值,不包括例項變數,例項變數將會在物件例項化的時候隨著物件一起分配在Java
堆中; - 解析:將常量池內的符號引用替換為直接引用的過程;
初始化:為類的靜態變數賦予正確的初始值,使得Java
程式碼中被顯式地賦予的值。
當我們要對基礎類進行修改時,打破雙親委託模型的方式:
- 自定義類載入器:繼承
ClassLoader
類重寫loadClass
方法。 - SPI機制:
JDK
內建的一種服務提供發現機制:通過載入ClassPath
下META_INF/services
,自動載入檔案裡所定義的類,通過ServiceLoader.load/Service.providers
方法通過反射拿到實現類的例項。
相關文章
- JVM筆記 -- Java跨平臺和JVM跨語言JVM筆記Java
- 筆記:JVM筆記JVM
- JVM讀書筆記之java記憶體結構JVM筆記Java記憶體
- java學習筆記-4 JVM垃圾回收(GC)Java筆記JVMGC
- jvm筆記1JVM筆記
- JVM學習筆記——初識JVMJVM筆記
- JVM學習筆記JVM筆記
- JVM筆記 -- JVM經歷了什麼?JVM筆記
- JVM核心學習筆記JVM筆記
- JVM 學習筆記(五)JVM筆記
- 今日學習JVM筆記JVM筆記
- JVM學習筆記-01JVM筆記
- Java的記憶體 -JVM 記憶體管理Java記憶體JVM
- JVM讀書筆記之OOMJVM筆記OOM
- Java學習筆記—開源框架Netty的簡單使用Java筆記框架Netty
- JVM的藝術—JAVA記憶體模型JVMJava記憶體模型
- JVM讀書筆記之記憶體管理JVM筆記記憶體
- JVM記憶體JAVA_OPTSJVM記憶體Java
- JVM學習筆記之棧區JVM筆記
- JVM筆記 -- JVM的發展以及基於棧的指令集架構JVM筆記架構
- java 筆記Java筆記
- JVM學習筆記---伺服器,JVM效能監控工具JVM筆記伺服器
- ☕【JVM技術指南】「JVM總結筆記」Java虛擬機器垃圾回收認知和調優的"思南(司南)"【下部】JVM筆記Java虛擬機
- 【Java筆記】Java JDKJava筆記JDK
- JVM學習筆記——自動記憶體管理JVM筆記記憶體
- Java 21的Pseudorandom的筆記Javarandom筆記
- 筆記資源整理筆記
- JVM學習筆記(3)---OutOfMemory詳解JVM筆記
- Java記憶體管理 -JVM 垃圾回收Java記憶體JVM
- 馬克筆記—Android 端開源的 Markdown 筆記應用筆記Android
- JVM 系列文章之 Java 的記憶體區域JVMJava記憶體
- JVM記憶體分配機制與回收策略選擇-JVM學習筆記(2)JVM記憶體筆記
- JVM筆記--如果你寫JVM,最需要考慮的重要結構是什麼?JVM筆記
- java 筆記(草稿)Java筆記
- Java安全筆記Java筆記
- Java筆記-反射Java筆記反射
- Java筆記1Java筆記
- Java筆記——【Map】Java筆記