成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

談一談JVM垃圾回收

stormzhang / 3662人閱讀

摘要:這個(gè)算法看似不錯而且簡單,不過存在這一個(gè)致命傷當(dāng)兩個(gè)對象互相引用的時(shí)候,就永遠(yuǎn)不會被回收于是引用計(jì)數(shù)算法就永遠(yuǎn)回收不了這兩個(gè)對象,下面介紹另一種算法。

前言

? 如果要問Java與其他編程語言最大的不同是什么,我第一個(gè)想到的一定就是Java所運(yùn)行的JVM所自帶的自動垃圾回收機(jī)制,以下是我學(xué)習(xí)JVM垃圾回收機(jī)制整理的筆記,希望能對讀者有一些幫助。

哪些內(nèi)存需要回收?what?

? 如何判斷對象已死?有兩種算法

引用計(jì)數(shù)算法

? 給對象添加一個(gè)計(jì)數(shù)器,每當(dāng)有一個(gè)地方引用它時(shí),計(jì)數(shù)器的值就加一,當(dāng)引用失效的時(shí)候,計(jì)數(shù)器就減一 ,任何時(shí)刻計(jì)數(shù)器為0的對象就是不可能再被使用的時(shí)候。

? 這個(gè)算法看似不錯而且簡單,不過存在這一個(gè)致命傷(當(dāng)兩個(gè)對象互相引用的時(shí)候,就永遠(yuǎn)不會被回收)

public class Obj{
  public Object instance=null;
}

Obj a=new Obj();
Obj b=new Obj();

a.instance=b;
b.instance=a;

a=null;
b=null;

于是引用計(jì)數(shù)算法就永遠(yuǎn)回收不了這兩個(gè)對象,下面介紹另一種算法。

可達(dá)性分析算法

? 通過一系列被稱為“GC Roots”的對象作為起始點(diǎn),從這些接點(diǎn)向下搜索,搜索所走過的路徑稱為引用鏈,當(dāng)一個(gè)對象與任何一個(gè)引用鏈沒有關(guān)聯(lián)的時(shí)候則可以被回收。

Java中,可作為GC Roots的對象包括下面集中

虛擬機(jī)棧(棧幀中的本地變量表)中引用的對象

方法區(qū)中類靜態(tài)屬性引用的對象

方法區(qū)中常量引用的對象

本地方法棧中JNI(Native方法)引用的對象

淺談引用

? 無論是計(jì)數(shù)器算法還是可達(dá)性分析算法,都與“引用”有關(guān),下面是Java中4種引用,強(qiáng)度依次減弱

強(qiáng)引用

? 強(qiáng)引用就是我們平時(shí)最熟悉的

Object obj=new Object();

? 只要強(qiáng)引用還存在,垃圾收集器永遠(yuǎn)不會回收掉被引用的對象。

軟引用

? 發(fā)生gc的時(shí)候,如果JVM內(nèi)存充足則不回收,用SoftReference類來實(shí)現(xiàn)軟引用。展示一個(gè)例子

        SoftReference softReference=new SoftReference<>(new Object());
        System.out.println("before gc  "+softReference.get());
        System.gc();
        System.out.println("after gc   "+softReference.get());

? 以下是輸出

before gc  java.lang.Object@2752f6e2
after gc   java.lang.Object@2752f6e2

可以看到軟引用的對象依然還在。

弱引用

? 一旦發(fā)生gc,無論JVM內(nèi)存充足與否,都會回收掉,用WeakReference類來實(shí)現(xiàn)弱引用。展示一個(gè)例子

        WeakReference softReference=new WeakReference<>(new Object());
        System.out.println("before gc  "+softReference.get());
        System.gc();
        System.out.println("after gc   "+softReference.get());

? 以下是輸出

before gc  java.lang.Object@2752f6e2
after gc   null

弱引用的對象已經(jīng)被回收!

虛引用

? 虛引用也稱為幽靈引用或者幻影引用,是最弱的一種引用,無法通過虛引用來取得一個(gè)對象實(shí)例,擁有虛引用的對象可以在任何時(shí)候被垃圾回收器回收。唯一的目的就是能在當(dāng)這個(gè)對象被回收的時(shí)候收到一個(gè)系統(tǒng)通知,可用PhantomReference類實(shí)現(xiàn)虛引用。

回收方法區(qū)

? 垃圾回收大多發(fā)生在Heap(堆區(qū)),因?yàn)樵诜椒▍^(qū)進(jìn)行垃圾回收效率較低,要判定一個(gè)類是否是“無用的類”條件比較苛刻,類需要同時(shí)滿足下面3個(gè)條件才能算是無用的類

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

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

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

什么時(shí)候回收?when?

? 首先,GC又分為minor GC 和 Full Gc(也稱為Major GC)。Java 堆內(nèi)存分為新生代和老年代,新生代中又分為1個(gè)Eden區(qū)域 和兩個(gè) Survivor區(qū)域。

那么對于 Minor GC 的觸發(fā)條件:大多數(shù)情況下,直接在 Eden 區(qū)中進(jìn)行分配。如果 Eden區(qū)域沒有足夠的空間,那么就會發(fā)起一次 Minor GC;對于 Full GC(Major GC)的觸發(fā)條件:也是如果老年代沒有足夠空間的話,那么就會進(jìn)行一次 Full GC。

注意:上面所說的只是一般情況,實(shí)際上,需要考慮一個(gè)空間分配擔(dān)保的問題:

在發(fā)生Minor GC之前,虛擬機(jī)會先檢查老年代最大可用的連續(xù)空間是否大于新生代所有對象的總空間。如果大于則進(jìn)行Minor GC,如果小于則看HandlePromotionFailure設(shè)置是否允許擔(dān)保失?。ú辉试S則直接Full GC)。如果允許,那么會繼續(xù)檢查老年代最大可用的連續(xù)空間是否大于歷次晉升到老年代對象的平均大小,如果大于則嘗試Minor GC(如果嘗試失敗也會觸發(fā)Full GC),如果小于則進(jìn)行Full GC。

System.gc()就是指的Full GC

但是,具體程序執(zhí)行到什么位置才會自動gc,這兒提兩個(gè)概念Safepoint和SafeRegion。

安全點(diǎn)(Safepoint)

? 安全點(diǎn)的選定是以程序“是否具有讓程序長時(shí)間執(zhí)行的特征”為標(biāo)準(zhǔn)選定的,“長時(shí)間執(zhí)行”最明顯的特征就是

指令序列復(fù)用

循環(huán)跳轉(zhuǎn)

異常跳轉(zhuǎn)等

對于Safepoint如何在GC發(fā)生時(shí)讓所有線程都跑到最近的安全點(diǎn)上停下來,有兩種方案搶先式中斷主動式中斷

搶先式中斷:不需要線程執(zhí)行的代碼主動配合,GC發(fā)生時(shí),首先把所有線程全部中斷,如果發(fā)現(xiàn)有線程中斷的地方不在安全點(diǎn)上,就恢復(fù)線程,讓它“跑到”安全點(diǎn)上。(這種方案幾乎很少使用)

主動式中斷 :當(dāng)GC需要中斷線程的時(shí)候,不直接對線程操作,僅僅簡單設(shè)置一個(gè)標(biāo)志,各個(gè)線程執(zhí)行時(shí)主動去輪詢這個(gè)標(biāo)志,發(fā)現(xiàn)為true就自動掛起,輪詢的地方和安全點(diǎn)是重合的。

安全區(qū)域(Saferegion)

? 當(dāng)線程處于Sleep狀態(tài)或者Blocked狀態(tài),這時(shí)候線程無法響應(yīng)JVM的中斷請求,“走”到安全的地方去中斷掛起,JVM也顯然不太可能等待線程重新被分配CPU時(shí)間,這時(shí)候就需要安全區(qū)域來解決。

? 當(dāng)線程執(zhí)行到Safe Region中的代碼時(shí),首先標(biāo)識自己已經(jīng)進(jìn)入了Safe Region,當(dāng)JVM在發(fā)起GC時(shí),就不用管標(biāo)識自己為Safe Region狀態(tài)的線程了。在線程要離開Safe Region時(shí),他要檢查系統(tǒng)是否完成了整個(gè)GC過程,如果完成了,線程就繼續(xù)執(zhí)行,否則必須等待直到收到可以安全離開Safe Region的信號為止。

如何回收?how? 標(biāo)記-清除 算法

? 算法分為標(biāo)記清除兩個(gè)階段,首先標(biāo)記出所有需要回收的對象,在標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對象。他的不足主要有兩個(gè):

效率問題:標(biāo)記和清除兩個(gè)過程的效率都不高

空間問題:標(biāo)記清除之后,會產(chǎn)生大量不連續(xù)的內(nèi)存碎片,空間碎片太多可能會導(dǎo)致之后分配大對象時(shí),無法找到足夠的連續(xù)內(nèi)存而提前觸發(fā)GC

復(fù)制算法

? 復(fù)制算法可以將容量劃分為大小相等的兩塊,每次只使用其中的一塊,當(dāng)一塊內(nèi)存被用完了就將還存活的對象一次復(fù)制到另一塊內(nèi)存上,然后把已經(jīng)使用過的內(nèi)存一次清理掉。不過因此內(nèi)存縮小為原來的一半,代價(jià)過高。

? 現(xiàn)在的商業(yè)虛擬機(jī)普遍采用這種算法來回收新生代,將新生代分為較大的一塊Eden空間和兩塊較小的Survivor空間,HotSpot默認(rèn)其比例為8:1:1,使用時(shí),每次使用Eden加上其中一塊Survivor,回收時(shí),將Eden和Survivor中還存活的對象一次性復(fù)制到另一塊Survivor中,最后清理掉Eden和剛才用過的Survivor區(qū)。

標(biāo)記-整理 算法

? 標(biāo)記過程與“標(biāo)記-清除”算法一樣,然后讓所有存活的對象都向同一端移動,然后直接清理端邊界以外的內(nèi)存。

分代收集算法

? 將Java堆分為新生代和老年代,在新生代中每次垃圾回收都有大批對象死去,少量存活,可以使用復(fù)制算法,而老年代中對象存活率高沒有額外的空間對它進(jìn)行分配擔(dān)保,必須使用“標(biāo)記-整理”或者“標(biāo)記-清理”算法來回收。

談?wù)凣1垃圾收集器

? 在最近更新的JDK9中,JVM默認(rèn)的垃圾收集器切換成了G1,那么G1有什么特點(diǎn)呢?總結(jié)以下最大的四個(gè)特點(diǎn)

并行與并發(fā):G1能充分利用多CPU、多核環(huán)境下的硬件優(yōu)勢,使用多個(gè)CPU,(CPU或者CPU核心)來縮短Stop-The-World停頓的時(shí)間,部分其他收集器需要停頓Java線程執(zhí)行的GC動作,G1可以通過并發(fā)的方式讓Java繼續(xù)執(zhí)行。

分代收集:G1不需要其他收集器配合就能獨(dú)立管理整個(gè)GC堆,G1采用不同的方式去處理新創(chuàng)建的對象、已經(jīng)存活一段時(shí)間的對象熬過多次GC的舊對象以獲取更好的收集效果。

空間整合:G1從整體來看是基于“標(biāo)記-整理”算法,局部上來看是基于復(fù)制算法,這兩種算法都不會產(chǎn)生內(nèi)存碎片,有利于程序長時(shí)間運(yùn)行。

可預(yù)測的停頓:G1除了追求低停頓外,還能建立可預(yù)測的停頓時(shí)間模型,能讓使用者明確指定在一個(gè)長度為M毫秒的時(shí)間片段內(nèi),消耗在垃圾收集上的時(shí)間不超過N毫秒。

資料來源
《深入理解Java虛擬機(jī)》P61-P84

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/69424.html

相關(guān)文章

  • js技術(shù) - 收藏集 - 掘金

    摘要:還記得剛開始學(xué)習(xí)的時(shí)候,內(nèi)存管理前端掘金作為一門高級語言,并不像低級語言那樣擁有對內(nèi)存的完全掌控。第三方庫的行代碼內(nèi)實(shí)現(xiàn)一個(gè)前端掘金前言本文會教你如何在行代碼內(nèi),不依賴任何第三方的庫,用純實(shí)現(xiàn)一個(gè)。 (譯) 如何使用 JavaScript 構(gòu)建響應(yīng)式引擎 —— Part 1:可觀察的對象 - 掘金原文地址:How to build a reactive engine in JavaSc...

    Guakin_Huang 評論0 收藏0
  • js技術(shù) - 收藏集 - 掘金

    摘要:還記得剛開始學(xué)習(xí)的時(shí)候,內(nèi)存管理前端掘金作為一門高級語言,并不像低級語言那樣擁有對內(nèi)存的完全掌控。第三方庫的行代碼內(nèi)實(shí)現(xiàn)一個(gè)前端掘金前言本文會教你如何在行代碼內(nèi),不依賴任何第三方的庫,用純實(shí)現(xiàn)一個(gè)。 (譯) 如何使用 JavaScript 構(gòu)建響應(yīng)式引擎 —— Part 1:可觀察的對象 - 掘金原文地址:How to build a reactive engine in JavaSc...

    zhou_you 評論0 收藏0
  • Java開發(fā) 大廠面試整理

    摘要:用戶態(tài)不能干擾內(nèi)核態(tài)所以指令就有兩種特權(quán)指令和非特權(quán)指令不同的狀態(tài)對應(yīng)不同的指令。非特權(quán)指令所有程序均可直接使用。用戶態(tài)常態(tài)目態(tài)執(zhí)行非特權(quán)指令。 這是我今年從三月份開始,主要的大廠面試經(jīng)過,有些企業(yè)面試的還沒來得及整理,可能有些沒有帶答案就發(fā)出來了,還請各位先思考如果是你怎么回答面試官?這篇文章會持續(xù)更新,請各位持續(xù)關(guān)注,希望對你有所幫助! 面試清單 平安產(chǎn)險(xiǎn) 飛豬 上汽大通 浩鯨科...

    Scorpion 評論0 收藏0
  • JavaScript運(yùn)行原理解析

    摘要:執(zhí)行過程引擎會加載源代碼,把它分解成字符串又叫做分詞,再把這些字符串轉(zhuǎn)換成編譯器可以理解的字節(jié)碼,然后執(zhí)行這些字節(jié)碼。接著四個(gè)進(jìn)程開始參與進(jìn)來,分析和執(zhí)行解析器所生成的字節(jié)碼。 JavaScript運(yùn)行原理 知其然,也要知其所以然,這里主要談一談對JavaScript運(yùn)行原理的理解。 JAVA虛擬機(jī) 首先我們從JAVA虛擬機(jī)說起。 首先說一下為什么要做成虛擬機(jī),因?yàn)闄C(jī)器不同,如果沒有虛...

    goji 評論0 收藏0
  • Java問題匯總,持續(xù)更新到GitHub

    摘要:目錄介紹問題匯總具體問題好消息博客筆記大匯總年月到至今,包括基礎(chǔ)及深入知識點(diǎn),技術(shù)博客,學(xué)習(xí)筆記等等,還包括平時(shí)開發(fā)中遇到的匯總,當(dāng)然也在工作之余收集了大量的面試題,長期更新維護(hù)并且修正,持續(xù)完善開源的文件是格式的同時(shí)也開源了生活博客,從年 目錄介紹 00.Java問題匯總 01.具體問題 好消息 博客筆記大匯總【16年3月到至今】,包括Java基礎(chǔ)及深入知識點(diǎn),Android技...

    beita 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<