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

資訊專欄INFORMATION COLUMN

JVM(2)--一文讀懂垃圾回收

MRZYD / 2221人閱讀

摘要:對象存不進去,會又一次觸發(fā)垃圾回收。也就是說,它在進行垃圾回收時,必須暫停其他所有線程。我們來看一個名詞吞吐量。吞吐量運行用戶代碼時間運行用戶代碼時間垃圾收集時間。也就是說,收集器會嚴格控制吞吐量,至于這個吞吐量是多少,這個可以人為設置。

與其他語言相比,例如c/c++,我們都知道,java虛擬機對于程序中產(chǎn)生的垃圾,虛擬機是會自動幫我們進行清除管理的,而像c/c++這些語言平臺則需要程序員自己手動對內(nèi)存進行釋放。

雖然這種自動幫我們回收垃圾的策略少了一定的靈活性,但卻讓代碼編寫者省去了很多工作,同時也提高了很多安全性。(因為像C/C++假如你創(chuàng)建了大量的對象,但卻由于自己的疏忽忘了將他們進行釋放,可能會造成內(nèi)存溢出)。

何為垃圾?

剛才說了,虛擬機會自動幫助我們進行垃圾的清除,那什么樣的對象我們才可以稱為是垃圾對象呢?

假如你創(chuàng)建了一個對象

Man m = new Man();

你用一個變量指向了這個對象,顯然對于這個對象,你可以用變量m對這個對象進行利用,但過了一段時間,你執(zhí)行了

m = null;

并且也并沒有新的變量來指向剛才創(chuàng)建的對象。此時對于這個沒有任何變量指向的對象,你覺得它還有用處嗎?

顯然,對于這種沒有被變量指向的對象,它是一點卵用也沒有的,它只能在隨風漂流。

因此,對于這樣的對象,我們就可以把它稱為垃圾了,它早晚會被垃圾回收器給干掉。

怎么知道它已經(jīng)是垃圾對象了?

假如代碼是你自己編寫的,你可能知道這個對象啥時候應該被拋棄,你可以隨時讓它成為垃圾對象。

但是,你畢竟是你,虛擬機則沒那么智能。那虛擬機是如何知道的呢?

上面已經(jīng)說了,沒有變量引用這個對象時,它就是垃圾對象了,基于這個原理,我們可以這樣做?。?/p>

我們可以為這個對象設置一個計數(shù)器,初始值為0,假如有一個變量指向它,那么計數(shù)器就加1,如果這個變量不在指向它了,計數(shù)器就減1。那么我們就可以判斷,如果這個計數(shù)器為0的話,那它就是垃圾對象了,否則就是有用的對象。

對于這種方法,我們稱之為引用計數(shù)法。

好吧,我們先來夸一夸引用計數(shù)法這種方法:

實現(xiàn)簡單。

效率高(一個if語句就能解決的問題想不高效都難)。

不好意思,接下來得說說它那個致命的缺點

實際上,對于這種引用計數(shù)的方法,假如它遇到對象互相引用的話,是很難解決的。

先看一段代碼:

Man m1 = new Man();
Man m2 = new Man();
//互相引用
m1.instance = m2;//假設Man有instance這個屬性
m2.instance = m1;

m1 = null;
m2 = null;
System.gc();//按道理對象應該被回收

這段代碼m1和m2都指向null了,按道理兩個對象已經(jīng)是無用對象,應該被回收,但是,兩個對象之間彼此有一個instance的屬性互相牽引的對方,導致兩個對象并沒有被回收。

這個缺點夠致命吧?

所以,虛擬機并沒有采用這種引用計數(shù)的方法。

可達性分析

除了這種方法,我們還有其他的方法嗎?

答案是有的,必須得有啊。這種方法就是傳說中的可達性分析,(我靠,聽名字是真的高級啊)。它的工作原理是這樣的:

在程序開始時,會建立一個引用根節(jié)點(GC Roots),并構建一個引用圖。當需要判斷誰是垃圾時,我們可以從這個根節(jié)點進行遍歷,如果沒有被遍歷到的節(jié)點則是垃圾對象,否則就是有用對象。如下圖:

這個方法可以解決循環(huán)相互引用的問題,但是這個方法并沒有引用計數(shù)法高效,畢竟要遍歷圖啊。

總結下判斷是否為垃圾對象的算法:

引用計數(shù)法。

可達性分析。

何時進行垃圾回收

可能有人會覺得這個問題很奇怪,覺得看到垃圾就回收不是很好。對于這個我只能說:

看到房間有一點垃圾你會馬上掃?還是等到某個時間點或者當垃圾積累到一定的數(shù)量再掃?

虛擬機可沒那么智能可以馬上識別這個對象是垃圾對象,它還得遍歷所有對象才能知道有哪些是垃圾對象。

所以說,你總不能幾秒(我們假設幾秒是賊短的時間)就讓虛擬機遍歷一下所有對象吧?

這里先說明一下,當垃圾回收器在進行垃圾回收的時候,為了保證垃圾回收不受干擾,是會暫停所有線程的,此時程序無法對外部的請求進行響應。(因為你想啊,當你在可達性分析的時候,那些引用關系還在不斷著變化,那不很難受)。

而且頻繁的垃圾回收,對于有一些程序,是很影響用戶體驗的,例如你在玩游戲,系統(tǒng)動不動就停頓一下,怕你是要把這游戲給刪了。

所以說,垃圾回收是會等到內(nèi)存被使用了一定的比例的時候,才會觸發(fā)垃圾回收。至于這個比例是多少,這可能就是人為規(guī)定的了。

怎么回收?

當我們標記好了哪些是垃圾,想要進行回收的時候,該怎么回收比較好呢?

可能有一些人就覺得奇怪,這還不簡單,看見它是垃圾,直接回收不就得了。

其實這也不無道理,簡單粗暴,直接回收。

是的,確實有這樣的算法,看哪些是被我們標記的垃圾,看見了就直接回收。這種算法我們稱之為標記--清除算法。

標記-清除算法工作原理:就是先標記出所有需要回收的對象,然后在統(tǒng)一回收所有被標記過的對象。

不過,那些人你可別得意啊,因為這種方法雖然簡單暴力,但它有個致命的缺點就是:

標記清除過后,會產(chǎn)生大量的不連續(xù)內(nèi)存碎片,如果不連續(xù)的碎片過多的話,,可能會導致有一些大的對象存不進去。這樣,會導致下面兩個問題:

有些內(nèi)存浪費了。

對象存不進去,會又一次觸發(fā)垃圾回收。

復制算法

為了解決這種問題,另外一種算法出現(xiàn)了---復制算法。就是說,它會將可用的內(nèi)存按容量劃分成兩塊。然后每次只使用其中的一塊,當這一塊快用完的時候,就會觸發(fā)垃圾回收,它會把還存活的對象全部復制到另外一塊內(nèi)存中去,然后把這塊內(nèi)存全部清理了。

這樣,就不會出現(xiàn)碎片問題了。

居然幫我們解決了我們必須夸一下它:不僅幫我們解決了問題,而且實現(xiàn)上也簡單、運行也高效。

但是(凡事都有個但是的),它也是有缺點的,缺點很明顯,發(fā)現(xiàn)了沒有。假如每次存活的對象都很少很少,那另外一塊內(nèi)存不是幾乎沒有用到?所以說,這種方法有可能導致另外一半內(nèi)存幾乎沒用了。內(nèi)存那么寶貴,這可是很嚴重的問題。

優(yōu)化策略:可以告訴你,有研究顯示,其實有98%的對象都是朝生夕死的,也就是說,每次存活的對象確實很少很少。既然我們都知道存活的對象很少很少了,那我們干嘛還1:1的比例來分配?所以說,HotShot虛擬機是默認按8:1的比例來分配的。這樣,就不會出現(xiàn)很多內(nèi)存沒用到的問題了。

可能有人會說,萬一占比為1/9的內(nèi)存不夠用了怎么辦?不就沒地方存那些活的對象?實際上,當內(nèi)存不夠用時,可以向其他地方借些內(nèi)存來使用,例如老年代里的內(nèi)存。

這里說明一下新生代和老年代:說白了,新生代就是剛剛創(chuàng)建不久的對象,而老年代是已經(jīng)活了挺久的對象。也就是說,有一些對象是確實活的比較久的,對于這種對象,我們另外給它分配內(nèi)存來養(yǎng)老,而且垃圾回收時,我們不用每次都來這里查找有沒垃圾對象,因為這些對象是垃圾的幾率會比較小。

下面在簡單介紹另外兩種算法:

標記-整理算法:這種算法和標記-清除算法類似,不過它把垃圾清除了之后,會讓存活的對象往一個方向靠攏,以此來整理碎片。

分代收集算法:所謂分代就是把對象分成類似上面說的老年代和新生代,在新手代一般每次垃圾回收時死的對象一般都會比較多,而老年代會比較少,基于這種關系,我們就可以采取不同的算法來針對了。

總結下垃圾回收的幾種算法:

標記-清除算法。

復制算法。

標記-整理算法。

分代收集算法。

最后給大家?guī)追N垃圾回收器

對于垃圾的回收,你是想一邊運行程序其他代碼一邊進行垃圾回收?還是想把垃圾全收好再來執(zhí)行程序的其他代碼?雖然說最終使用cpu的時間是一樣,但兩種方式還是有區(qū)別的。

下面簡單介紹幾種垃圾回收器,看看他們都使用哪種方。

(1).Serial收集器

serial(串行),看這個英文單詞就知道這是一個單線程收集器。也就是說,它在進行垃圾回收時,必須暫停其他所有線程。顯然,有時垃圾回收停頓的比較久的話,這對于用戶來說是很難受的。

(2).ParNew

這個收集器和Serial很類似,進行垃圾回收的時候,也是得暫停其他所有線程,不過,它可以多條線程工作進行垃圾回收。

(3).Parallel Scavenge收集器

parallel,并行的意思。也是可以多線程進行垃圾回收處理,但是它與ParNew不同。它會嚴格控制垃圾回收的時間與執(zhí)行其他代碼的時間之間的比例。我們來看一個名詞:吞吐量

吞吐量 = 運行用戶代碼時間 / (運行用戶代碼時間 + 垃圾收集時間)。

也就是說,Parallet Scavenge收集器會嚴格控制吞吐量,至于這個吞吐量是多少,這個可以人為設置。

下面兩個收集器重點介紹下

(4).CMS(Concurrent Mark Sweep)收集器

CMS收集器是基于“標記-清除”算法實現(xiàn)的,它的運作過程相對于前面幾種收集器來說要更復雜一些,整個過程分為4個步驟,包括:

初始標記(CMS initial mark)

并發(fā)標記(CMS concurrent mark)

重新標記(CMS remark)

并發(fā)清除(CMS concurrent sweep)

其中初始標記、重新標記這兩個步驟仍然需要暫停其他線程。但另外兩個步驟可以和其他線程并發(fā)執(zhí)行。初始標記僅僅只是標記一下GCRoots能直接關聯(lián)到的對象,速度很快,并發(fā)標記階段就是進行GC Roots Tracing的過程 (說白了就是把整個圖都遍歷了,找出沒有的對象),

而重新標記階段則是為了修正并發(fā)標記期間,因用戶程序繼續(xù)運作而導致標記產(chǎn)生變動的那一部分對象的標記記錄,這個階段的停頓時間一般會比初始標記階段稍長一些,但遠比并發(fā)標記的時間短。

由于整個過程中耗時最長的并發(fā)標記和并發(fā)清除過程中,收集器線程都可以與用戶線程一起工作,所以總體上來說,CMS收集器的內(nèi)存回收過程幾乎是與與用戶線程一起并發(fā)地執(zhí)行。

(5).G1收集器

這個估計是最牛的收集器了。該收集器具有如下特點:

并行與并發(fā):G1能充分利用現(xiàn)代計算器多CPU,多核的硬件優(yōu)勢,可以使用并發(fā)或并行的方式來縮短讓其他線程暫停的優(yōu)勢。

分代收集:就是類似像分出新生代和老年代那樣處理。

空間整合:采用了復制算法+標記-整合算法的特點來回收垃圾。就是整體采用標記-整理算法,局部采用復制算法。

可預測停頓:這個就牛了,就是說,它能讓使用者明確指定在一個長度為M毫秒的時間片段內(nèi),消耗在垃圾收集上的時間不超過N毫秒。

它的執(zhí)行過程大體如下:

初始標記。

并發(fā)標記。

最終標記。

篩選回收。

這個流程和CMS很相似,它也是在初始標記最終標記需要暫停其他線程,但其他兩個過程就可以和其他線程并發(fā)執(zhí)行。

剛才我們說了G1收集器哪些優(yōu)點,例如可預測停頓,這也使得篩選回收,是可以預測停頓垃圾回收的時間的,也就是說,停頓的時間是用戶自己可以控制的,這也使得一般情況下,在篩選回收的時候,我們會暫停其他線程的執(zhí)行,把所有時間都用到篩選回收上。

本次講解到這里。

關注公我的眾號:苦逼的碼農(nóng),獲取更多原創(chuàng)文章,后臺回復"禮包"送你一份特別的資源大禮包。

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

轉載請注明本文地址:http://systransis.cn/yun/76844.html

相關文章

  • 一文了解JVM

    摘要:而使用虛擬機是實現(xiàn)這一特點的關鍵。每個字節(jié)碼指令都由一個字節(jié)的操作碼和附加的操作數(shù)組成。字節(jié)碼可以通過以下兩種方式轉換成合適的語言解釋器一條一條地讀取,解釋并執(zhí)行字節(jié)碼執(zhí)行,所以它可以很快地解釋字節(jié)碼,但是執(zhí)行起來會比較慢。 一、什么是JVM JVM是Java Virtual Machine(Java 虛擬機)的縮寫,JVM是一種用于計算設備的規(guī)范,它是一個虛構出來的計算機,是通過在實...

    whatsns 評論0 收藏0
  • 一文了解JVM全部垃圾回收器,從Serial到ZGC

    摘要:是目前的實驗收集器。也是需要暫停程序一切的工作,然后多線程執(zhí)行垃圾回收。與最大的不同,它關注的是垃圾回收的吞吐量。這里的吞吐量指的是總時間與垃圾回收時間的比例。篩選回收,評估標記垃圾,根據(jù)模式回收垃圾。 《對象搜索算法與回收算法》介紹了垃圾回收的基礎算法,相當于垃圾回收的方法論。接下來就詳細看看垃圾回收的具體實現(xiàn)。 上文提到過現(xiàn)代的商用虛擬機的都是采用分代收集的,不同的區(qū)域用不同的收集...

    jasperyang 評論0 收藏0
  • 必知必會JVM垃圾回收——對象搜索算法與回收算法

    垃圾回收(GC)是JVM的一大殺器,它使程序員可以更高效地專注于程序的開發(fā)設計,而不用過多地考慮對象的創(chuàng)建銷毀等操作。但是這并不是說程序員不需要了解GC。GC只是Java編程中一項自動化工具,任何一個工具都有它適用的范圍,當超出它的范圍的時候,可能它將不是那么自動,而是需要人工去了解與適應地適用。 擁有一定工作年限的程序員,在工作期間肯定會經(jīng)常碰到像內(nèi)存溢出、內(nèi)存泄露、高并發(fā)的場景。這時候在應對這...

    LuDongWei 評論0 收藏0
  • Java11的新特性

    摘要:從版本開始,不再單獨發(fā)布或者版本了,有需要的可以自己通過去定制官方解讀官方細項解讀穩(wěn)步推進系列六的小試牛刀一文讀懂的為何如此高效棄用引擎 Java語言特性系列 Java5的新特性 Java6的新特性 Java7的新特性 Java8的新特性 Java9的新特性 Java10的新特性 Java11的新特性 Java12的新特性 Java13的新特性 序 本文主要講述一下Java11的新...

    April 評論0 收藏0
  • Java基礎篇——JVM之GC原理(干貨滿滿)

    摘要:此外,從結果我們可以得知,一個堆對象的放在局部變量表中的第一項引用會永遠存在,在方法體內(nèi)可以將引用賦值給其他變量,這樣堆中對象就可以被其他變量所引用,即不會被回收。 原創(chuàng)不易,如需轉載,請注明出處https://www.cnblogs.com/baixianlong/p/10697554.html,多多支持哈! 一、什么是GC? GC是垃圾收集的意思,內(nèi)存處理是編程人員容易出現(xiàn)問題的地...

    liaorio 評論0 收藏0

發(fā)表評論

0條評論

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