JVM執(zhí)行引擎和垃圾回收要點總結(jié)
一、執(zhí)行引擎
應(yīng)用程序經(jīng)過編譯,轉(zhuǎn)換為字節(jié)碼文件,字節(jié)碼加載到內(nèi)存空間并不能直接在操作系統(tǒng)上執(zhí)行,執(zhí)行引擎作為Java虛擬機(jī)核心的組成部分,作用就是將字節(jié)碼指令解釋/編譯為對應(yīng)系統(tǒng)平臺上的本地機(jī)器指令。

解釋器:虛擬機(jī)啟動時會根據(jù)預(yù)定義對字節(jié)碼采用逐行解釋的方式執(zhí)行,將每條字節(jié)碼文件中的內(nèi)容解釋為對應(yīng)系統(tǒng)平臺的本地機(jī)器指令執(zhí)行;
JIT編譯器:虛擬機(jī)將源代碼編譯成本地機(jī)器平臺相關(guān)的機(jī)器語言,并且尋找熱點高頻執(zhí)行的代碼將其放入元空間中,即元空間中存放的JIT緩存代碼;
垃圾回收:對于沒有任何引用的對象標(biāo)記為垃圾,會被回收釋放內(nèi)存空間。
二、垃圾對象標(biāo)記
1、引用計數(shù)法
每個對象保存一個整型引用計數(shù)器,用來記錄對象被引用的次數(shù),當(dāng)該對象被一個對象引用時,計數(shù)器加1,當(dāng)失去一個引用時,計數(shù)器減1;引用計數(shù)算法就是通過判斷對象的引用數(shù)量來決定對象是否可以被當(dāng)做垃圾對象回收掉。
雖然引用計數(shù)法效率高,但是當(dāng)兩個對象互相引用時會導(dǎo)致這兩個對象一直不會被回收,這是一個致命的缺陷。所以JVM并沒有采用該標(biāo)記算法。
2、可達(dá)性分析算法
可達(dá)性分析算法是基于對象到根對象的引用鏈?zhǔn)欠窨蛇_(dá)來判斷對象是否可以被回收;

運行程序把所有的引用關(guān)系鏈看作一張圖,通過GC-Roots根對象對象集合作為起始點,從每個根節(jié)點向下不斷搜索被根對象集合所連接的對象是否可達(dá),搜索路徑稱為引用鏈(Reference-Chain),如果對象到GC-Roots沒有任何引用鏈存在,則說明此對象是不可用的,
- 虛擬機(jī)棧中引用的對象;
- 元空間中類靜態(tài)屬性引用的對象;
- 元空間中常量引用的對象;
- 本地方法棧中Native方法引用的對象;
相對于引用計數(shù)法算法,可達(dá)性分析算法則避免了循環(huán)引用導(dǎo)致的問題,同樣具備執(zhí)行高效的特點,也是JVM采用的標(biāo)記算法。
三、垃圾回收機(jī)制
1、標(biāo)記清除算法
標(biāo)記-清除算法分為標(biāo)記和清除兩個階段:
標(biāo)記階段:從根對象集合進(jìn)行掃描,對存活的對象對象標(biāo)記;清除階段:再次掃描發(fā)現(xiàn)未被標(biāo)記的對象并進(jìn)行回收;

該算法效率不高,進(jìn)行垃圾回收需要暫停應(yīng)用程序,同時會產(chǎn)生大量內(nèi)存碎片,后續(xù)程序運行過程中分配內(nèi)存占用較大的對象時,會有連續(xù)內(nèi)存不夠情況,容易觸發(fā)再一次垃圾收集動作。
2、標(biāo)記整理算法
標(biāo)記整理算法的標(biāo)記過程類似標(biāo)記清除算法,第一階段:標(biāo)記出垃圾對象;第二階段:讓所有存活的對象都向內(nèi)存區(qū)一端移動;第三階段:直接清理掉邊界端以外的內(nèi)存,類似于磁盤整理的過程;

該垃圾回收算法效率不高,對象移動過程需要暫停應(yīng)用程序,適用于對象存活率高的場景(老年代)。
3、復(fù)制算法
復(fù)制算法將內(nèi)存按容量劃分為大小相等的兩塊,每次只使用其中的一塊,當(dāng)使用的這塊的內(nèi)存用完,就將還存活著的對象復(fù)制到另外一塊空閑內(nèi)存上,然后使用過的內(nèi)存空間一次清理。

該算法實現(xiàn)簡單,運行效率高,但是內(nèi)存空間嚴(yán)重浪費,適用于對象存活率低的場景,比如新生代。
4、分代收集算法
當(dāng)前市場上幾乎所有的虛擬機(jī)都采用該回收算法,分代收集算法根據(jù)年輕代和老年代的各自特點采用不同的算法機(jī)制,不同內(nèi)存區(qū)域中對象生命周期也不同,因此對堆內(nèi)存不同區(qū)域采用不同的回收策略可以提高垃圾回收執(zhí)行效率。通常情況新生代對象存活率低,回收頻繁,就采用復(fù)制算法;老年代存對象生命周期長,活率高,就用標(biāo)記清除算法或者標(biāo)記整理算法。
Java堆內(nèi)存一般可以分為新生代、老年代和永久代三個模塊,如下圖所示:

新生代
通常情況下,新創(chuàng)建的對象實例首先都是放在新生代空間中,所以追求快速的回收掉垃圾對象,一般情況下,新生代內(nèi)存按照8:1:1的比例分為一個eden區(qū)和兩個survivor(survivor0,survivor1)區(qū),對象實例大部分在Eden區(qū)中生成;
垃圾回收時先把eden區(qū)存活對象復(fù)制到S0區(qū),然后清空eden區(qū),當(dāng)S0區(qū)也滿時,再將eden區(qū)和S0區(qū)存活對象復(fù)制到S1區(qū),然后清空eden和S0區(qū),之后交換S0區(qū)和S1區(qū)的角色,當(dāng)S1區(qū)無法存放eden區(qū)和S0區(qū)的存活對象時,就將存活對象直接存移到老年代區(qū),當(dāng)老年代區(qū)也滿了,觸發(fā)一次FullGC,即新生代、老年代都進(jìn)行回收。
老年代
老年代區(qū)存放一些生命周期較長的對象,對象實例在新生代中經(jīng)歷了多次垃圾回收仍然存活的對象,會被移動到老年代區(qū)中。
四、源代碼地址
GitHub·地址
https://github.com/cicadasmile/java-base-parent
GitEE·地址
https://gitee.com/cicadasmile/java-base-parent
以上就是JVM執(zhí)行引擎和垃圾回收要點總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于JVM執(zhí)行引擎和垃圾回收的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java設(shè)計模式七大原則之合成復(fù)用原則詳解
合成復(fù)用原則(Composite Reuse Principle),即盡量使用組合/聚合的方式,而不是使用繼承。本文將為大家具體介紹一下Java設(shè)計模式七大原則之一的合成復(fù)用原則,需要的可以參考一下2022-02-02
IDEA工程運行時總是報xx程序包不存在實際上包已導(dǎo)入(問題分析及解決方案)
這篇文章主要介紹了IDEA工程運行時,總是報xx程序包不存在,實際上包已導(dǎo)入,本文給大家分享問題分析及解決方案,通過實例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2020-08-08
spring?java?動態(tài)獲取consul?K/V的方法
這篇文章主要介紹了spring?java?動態(tài)獲取consul?K/V的相關(guān)資料,主要包括springConsul配置kv路徑以及自動注入consulKV到服務(wù)中,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10
Java的優(yōu)先隊列PriorityQueue原理及實例分析
這篇文章主要介紹了Java的優(yōu)先隊列PriorityQueue原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-12-12
SpringBoot入坑筆記之spring-boot-starter-web 配置文件的使用
本篇向小伙伴介紹springboot配置文件的配置,已經(jīng)全局配置參數(shù)如何使用的。需要的朋友跟隨腳本之家小編一起學(xué)習(xí)吧2018-01-01
Spring Security 自定義短信登錄認(rèn)證的實現(xiàn)
這篇文章主要介紹了Spring Security 自定義短信登錄認(rèn)證的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03

