欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JVM的垃圾回收算法工作原理詳解

 更新時間:2019年06月19日 09:02:28   作者:clawhub  
這篇文章主要介紹了JVM的垃圾回收算如何判斷對象是否可以被回收,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,,需要的朋友可以參考下

怎么判斷對象是否可以被回收?

共有2種方法,引用計(jì)數(shù)法和可達(dá)性分析

1.引用計(jì)數(shù)法

所謂引用計(jì)數(shù)法就是給每一個對象設(shè)置一個引用計(jì)數(shù)器,每當(dāng)有一個地方引用這個對象時,就將計(jì)數(shù)器加一,引用失效時,計(jì)數(shù)器就減一。當(dāng)一個對象的引用計(jì)數(shù)器為零時,說明此對象沒有被引用,也就是“死對象”,將會被垃圾回收.

引用計(jì)數(shù)法有一個缺陷就是無法解決循環(huán)引用問題,也就是說當(dāng)對象A引用對象B,對象B又引用者對象A,那么此時A,B對象的引用計(jì)數(shù)器都不為零,也就造成無法完成垃圾回收,所以主流的虛擬機(jī)都沒有采用這種算法。

public classReferenceFindTest{
publicstaticvoidmain(String[] args){
MyObject object1 = new MyObject();
MyObject object2 = new MyObject();
object1.object = object2;
object2.object = object1;
object1 = null;
object2 = null;
}
}

2.可達(dá)性算法(引用鏈法)

該算法的思想是:從一個被稱為GC Roots的對象開始向下搜索,如果一個對象到GC Roots沒有任何引用鏈相連時,則說明此對象不可用。

在java中可以作為GC Roots的對象有以下幾種:

  • 虛擬機(jī)棧中引用的對象
  • 方法區(qū)類靜態(tài)屬性引用的對象
  • 方法區(qū)常量池引用的對象
  • 本地方法棧JNI引用的對象

雖然這些算法可以判定一個對象是否能被回收,但是當(dāng)滿足上述條件時,一個對象比不一定會被回收。當(dāng)一個對象不可達(dá)GC Root時,這個對象并不會立馬被回收,而是出于一個死緩的階段,若要被真正的回收需要經(jīng)歷兩次標(biāo)記。

如果對象在可達(dá)性分析中沒有與GC Root的引用鏈,那么此時就會被第一次標(biāo)記并且進(jìn)行一次篩選,篩選的條件是是否有必要執(zhí)行finalize()方法。當(dāng)對象沒有覆蓋finalize()方法或者已被虛擬機(jī)調(diào)用過,那么就認(rèn)為是沒必要的。

如果該對象有必要執(zhí)行finalize()方法,那么這個對象將會放在一個稱為F-Queue的對隊(duì)列中,虛擬機(jī)會觸發(fā)一個Finalize()線程去執(zhí)行,此線程是低優(yōu)先級的,并且虛擬機(jī)不會承諾一直等待它運(yùn)行完,這是因?yàn)槿绻鹒inalize()執(zhí)行緩慢或者發(fā)生了死鎖,那么就會造成F-Queue隊(duì)列一直等待,造成了內(nèi)存回收系統(tǒng)的崩潰。GC對處于F-Queue中的對象進(jìn)行第二次被標(biāo)記,這時,該對象將被移除”即將回收”集合,等待回收。

堆內(nèi)存分代策略以及意義

策略

Java虛擬機(jī)將堆內(nèi)存劃分為新生代、老年戰(zhàn)和永久代,永久代是HotSpaot 虛擬機(jī)特有的概念,它采用永久代的方式來實(shí)現(xiàn)方法區(qū),其他的虛擬機(jī)實(shí)現(xiàn)沒有這一概念,而且HotSpot也有取消永久代的趨勢,在JDK 1.7中HotSpot已經(jīng)開始了“去永久化”,把原本放在永久代的字符串常量池移出。永久代主要存放常量、類信息、靜態(tài)變量等數(shù)據(jù)(移植到方法區(qū)),與垃圾回收關(guān)系不大,新生代和老年代是垃圾回收的主要區(qū)域。

新生代(Young)

新生成的對象優(yōu)先存放在新生代中,新生代對象朝生夕死,存活率很低,在新生代中,常規(guī)應(yīng)用進(jìn)行一次垃圾收集-般可以回收70% ~ 95%的空間,回收效率很高。

老年代(OldGenerationn)

在新生代中經(jīng)歷了多次(具體看虛擬機(jī)配置的閥值)GC后仍然存活下來的對象會進(jìn)入老年代中。老年代中的對象生命周期較長,存活率比較高,在老年代中進(jìn)行GC的頻率相對而言較低,而且回收的速度也比較慢。

永久代(PermanentGenerationn)

永久代存儲類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù),對這一區(qū)域而言,Java虛擬機(jī)規(guī)范指出可以不進(jìn)行垃圾收集,一般而言不會進(jìn)行垃圾回收。

  • Jdk1.6及之前: 有永久代, 常量池1.6在方法區(qū)。
  • Jdk1.7: 有永久代,但已經(jīng)逐步“去永久代”,常量池1.7在堆。
  • Jdk1.8及之后: 無永久代,常量池1.8在元空間。而元空間是直接存在內(nèi)存中,不在java虛擬機(jī)中的,因此元空間依賴于內(nèi)存大小。當(dāng)然你也可以自定義元空間大小。

意義

有了內(nèi)存分代,新創(chuàng)建的對象會在新生代中分配內(nèi)存,經(jīng)過多次回收仍然存活下來的對象存放在老年代中,靜態(tài)屬性、類信息等存放在永久代中,新生代中的對象存活時間短,只需要在新生代區(qū)域中頻繁進(jìn)行GC,老年代中對象生命周期長,內(nèi)存回收的頻率相對較低,不需要頻繁進(jìn)行回收,永久代中回收效果太差, 一般不進(jìn)行垃圾回收,還可以根據(jù)不同年代的特點(diǎn),采用不同的垃圾收集算法。分代垃圾收集大大提升了垃圾收集效率,這些都是JVM分代的好處。

垃圾回收算法

1.復(fù)制算法

復(fù)制算法將可用內(nèi)存按容量劃分為相等的兩部分,然后每次只使用其中的一塊,當(dāng)一塊內(nèi)存用完時,就將還存活的對象復(fù)制到第二塊內(nèi)存上,然后一次性清楚完第一塊內(nèi)存,再將第二塊上的對象復(fù)制到第一塊。但是這種方式,內(nèi)存的代價太高,每次基本上都要浪費(fèi)一半的內(nèi)存。

2.標(biāo)記清除算法

是JVM垃圾回收算法中最古老的一個,該算法共分成兩個階段,第一階段從引用根節(jié)點(diǎn)開始標(biāo)記所有被引用的對象,第二階段遍歷整個堆,清除未被標(biāo)記的對象。該算法的缺點(diǎn)是需要暫停整個應(yīng)用,并且在回收以后未使用的空間是不連續(xù),即內(nèi)存碎片,會影響到存儲。

3.標(biāo)記整理算法

此算法結(jié)合了標(biāo)記-清楚算法和復(fù)制算法的優(yōu)點(diǎn),也分為兩個階段,第一階段從引用根節(jié)點(diǎn)開始標(biāo)記所有被引用的對象,第二階段遍歷整個堆,在回收不存活的對象占用的空間后,會將所有的存活對象往左端空閑空間移動,并更新對應(yīng)的指針。標(biāo)記-整理算法是在標(biāo)記-清除算法的基礎(chǔ)上,又進(jìn)行了對象的移動,因此成本更高,但是卻解決了內(nèi)存碎片的問題,按順序排放,同時解決了復(fù)制算法所需內(nèi)存空間過大的問題。

4.分代收集

分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根據(jù)對象存活的生命周期將內(nèi)存劃分為若干個不同的區(qū)域。一般情況下將堆區(qū)劃分為老年代(Tenured Generation)和新生代(Young Generation),在堆區(qū)之外還有一個代就是永久代(Permanet Generation)。老年代的特點(diǎn)是每次垃圾收集時只有少量對象需要被回收,而新生代的特點(diǎn)是每次垃圾回收時都有大量的對象需要被回收,那么就可以根據(jù)不同代的特點(diǎn)采取最適合的收集算法。

a.年輕代回收算法(核心其實(shí)就是復(fù)制算法)

HotSpot將新生代劃分為三塊,-塊較大的Eden空間和兩塊較小的Survivor空間,默認(rèn)比例為8: 1: 1。劃分的目的是因?yàn)镠otSpot采用復(fù)制算法來回收新生代,設(shè)置這個比例是為了充分利用內(nèi)存空間,減少浪費(fèi)。新生成的對象在Eden區(qū)分配(大對象除外,大對象直接進(jìn)入老年代) ,當(dāng)Eden區(qū)沒有足夠的空間進(jìn)行分配時,虛擬機(jī)將發(fā)起一次Minor GC。GC開始時,對象只會存在于Eden區(qū)和From Survivor區(qū),To Survivor區(qū)是空的(作為保留區(qū)域)。

GC進(jìn)行時,Eden區(qū)中所有存活的對象都會被復(fù)制到To Survivor區(qū),而在FromSurvivor區(qū)中,仍存活的對象會根據(jù)它們的年齡值決定去向,年齡值達(dá)到閥值(默認(rèn)為15 ,新生代中的對象每熬過一輪垃圾回收年齡值就加1 ,GC分代年齡存儲在對象的header中)的對象會被移到老年代中,沒有達(dá)到閥值的對象會被復(fù)制到To Survivor區(qū)。

接著清空Eden區(qū)和From Survivor區(qū),新生代中存活的對象都在To Survivor區(qū)。接著, From Survivor區(qū)和To Survivor區(qū)會交換它們的角色,也就是新的To Survivor區(qū)就是上次GC清空的FromSurvivor區(qū),新的From Survivor區(qū)就是.上次GC的To Survivor區(qū),總之,不管怎樣都會保證To Survivor區(qū)在一輪GC后是空的(其實(shí)這就是分代收集算法中的年輕代回收算法,稍后我們會看到)。

GC時當(dāng)To Survivor區(qū)沒有足夠的空間存放上一次新生代收集下來的存活對象時,需要依賴?yán)夏甏M(jìn)行分配擔(dān)保,將這些對象存放在老年代中。

b.老年代回收算法(回收主要以標(biāo)記-整理為主)

1)在年輕代中經(jīng)歷了N次垃圾回收后仍然存活的對象,就會被放到年老代中。因此,可以認(rèn)為年老代中存放的都是一些生命周期較長的對象。

2)內(nèi)存比新生代也大很多(大概比例是1:2),當(dāng)老年代內(nèi)存滿時觸發(fā)Major GC即Full GC,F(xiàn)ull GC發(fā)生頻率比較低,老年代對象存活時間比較長,存活率標(biāo)記高。

c. 持久代(Permanent Generation)的回收算法

用于存放靜態(tài)文件,如Java類、方法等。持久代對垃圾回收沒有顯著影響,但是有些應(yīng)用可能動態(tài)生成或者調(diào)用一些class,例如Hibernate 等,在這種時候需要設(shè)置一個比較大的持久代空間來存放這些運(yùn)行過程中新增的類。在該區(qū)內(nèi)很少發(fā)生垃圾回收,但是并不代表不發(fā)生GC,在這里進(jìn)行的GC主要是對持久代里的常量池和對類型的卸載。

條件:

1)該類所有的實(shí)例都已經(jīng)被回收,即Java堆中不存在該類的任何實(shí)例;

2)加載該類的ClassLoader已經(jīng)被回收;

3)該類對應(yīng)的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法。

虛擬機(jī)可以對滿足上述3個條件的無用類進(jìn)行回收,此處僅僅是“可以”,而并不是和對象一樣,不使用了就必然回收!

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • java泛型基本知識及通用方法

    java泛型基本知識及通用方法

    這篇文章主要介紹了java泛型基礎(chǔ)知識及通用方法,從以下幾個方面介紹一下java的泛型: 基礎(chǔ), 泛型關(guān)鍵字, 泛型方法, 泛型類和接口,感興趣的可以了解一下
    2019-04-04
  • Reactor 多任務(wù)并發(fā)執(zhí)行且結(jié)果按順序返回第一個

    Reactor 多任務(wù)并發(fā)執(zhí)行且結(jié)果按順序返回第一個

    這篇文章主要介紹了Reactor 多任務(wù)并發(fā)執(zhí)行且結(jié)果按順序返回第一個,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,感興趣的小伙伴可以參考一下
    2022-09-09
  • 編寫Java代碼對HDFS進(jìn)行增刪改查操作代碼實(shí)例

    編寫Java代碼對HDFS進(jìn)行增刪改查操作代碼實(shí)例

    這篇文章主要介紹了Java代碼對HDFS進(jìn)行增刪改查操作,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • SpringBoot中使用@scheduled定時執(zhí)行任務(wù)的坑

    SpringBoot中使用@scheduled定時執(zhí)行任務(wù)的坑

    本文主要介紹了SpringBoot中使用@scheduled定時執(zhí)行任務(wù)的坑,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • Java如何基于okhttp請求SSE接口流式返回詳解

    Java如何基于okhttp請求SSE接口流式返回詳解

    對于流式返回,Spring Boot提供了兩種不同的方式,下面這篇文章主要給大家介紹了關(guān)于Java如何基于okhttp請求SSE接口流式返回的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-03-03
  • Spring如何使用注解的方式創(chuàng)建bean

    Spring如何使用注解的方式創(chuàng)建bean

    這篇文章主要介紹了Spring如何使用注解的方式創(chuàng)建bean,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11
  • Spring Boot2.X國際化文件編寫配置

    Spring Boot2.X國際化文件編寫配置

    這篇文章主要介紹了Spring Boot2.X國際化文件編寫配置,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-02-02
  • IntelliJ IDEA 安裝 Grep Console插件 自定義控制臺輸出多顏色格式功能

    IntelliJ IDEA 安裝 Grep Console插件 自定義控制臺輸出多顏色格式功能

    由于Intellij idea不支持顯示ascii顏色,grep-console插件能很好的解決這個問題,下面就以開發(fā)JavaEE項(xiàng)目中,結(jié)合Log4j配置多顏色日志輸出功能,感興趣的朋友一起看看吧
    2020-05-05
  • Java實(shí)現(xiàn)word/pdf轉(zhuǎn)html并在線預(yù)覽

    Java實(shí)現(xiàn)word/pdf轉(zhuǎn)html并在線預(yù)覽

    這篇文章主要為大家詳細(xì)介紹了如何利用Java語言實(shí)現(xiàn)word、pdf文件轉(zhuǎn)html并在線預(yù)覽的功能,文中的示例代碼講解詳細(xì),需要的可以參考一下
    2023-05-05
  • java開發(fā)的工廠方法模式及抽象工廠驗(yàn)證示例

    java開發(fā)的工廠方法模式及抽象工廠驗(yàn)證示例

    這篇文章主要為大家介紹了java開發(fā)中的工廠方法模式以及抽象工廠的驗(yàn)證示例,有需要的朋友可以借鑒參考下希望能夠有所幫助祝大家多多進(jìn)步
    2021-10-10

最新評論