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

資訊專欄INFORMATION COLUMN

Java 垃圾回收(GC) 泛讀

haoguo / 525人閱讀

摘要:在這種消耗很高的狀態(tài)下,應(yīng)用程序所有的線程都會掛起,暫停一切正常的工作,等待垃圾回收的完成。但是,因為線程切換和上下文轉(zhuǎn)換的消耗,會使得垃圾回收的總體成本上升,造成系統(tǒng)吞吐量的下降。

Java 垃圾回收(GC) 泛讀

文章地址: https://segmentfault.com/a/1190000008922319

0. 序言

帶著問題去看待 垃圾回收(GC) 會比較好,一般來說主要的疑惑在于這么幾點:

為什么需要 GC ?

虛擬機(jī)(JVM) 與 垃圾回收(GC) 的關(guān)系?

GC 的原理有哪些?

哪些 對象容易被 GC ?

等等

帶著這些問題往下看:

1. 為什么需要 GC ?

GC: 是Garbage Collection 的英文縮略,垃圾收集的意思。

為什么需要 GC?
主要是隨著應(yīng)用程序所應(yīng)對的業(yè)務(wù)越來越龐大、復(fù)雜,用戶越來越多,沒有GC就不能保證應(yīng)用程序正常進(jìn)行。

為什么經(jīng)常討論 GC,沒有完美的解決方案嗎?
完美的解決方法目前還沒有。由于在 GC 時需要STW(Stop The World),這長不能滿足實際的需求,容易造成卡頓、延遲等性能問題,所以才會不斷地嘗試對GC進(jìn)行優(yōu)化。社區(qū)的需求是盡量減少對應(yīng)用程序的正常執(zhí)行干擾,這也是業(yè)界目標(biāo)。

2. 虛擬機(jī)(JVM) 與 GC 的關(guān)系 ?

以 HotSpotJVM 為例描述下 GC 在 JVM 中的位置:

由于 不同的 JVM 會有不同的 GC 實現(xiàn),不同的 GC 實現(xiàn)使用的算法又不盡相同,這才造成了 GC 的多樣性。
在收購SUN之前,Oracle使用的是JRockit JVM,收購之后使用HotSpot JVM。目前Oracle擁有兩種JVM實現(xiàn)并且一段時間后兩個JVM實現(xiàn)會合二為一。
HotSpot JVM是目前Oracle SE平臺標(biāo)準(zhǔn)核心組件的一部分。
最新的 GC 方案是 Garbage First(一般簡稱為 G1)。

3. GC 的種類 1. GC 的發(fā)展歷程

1999年隨JDK1.3.1一起來的是串行方式的Serial GC ,它是第一款 GC 。

2002年2月26日,J2SE1.4發(fā)布,Parallel GC 和Concurrent Mark Sweep (CMS)GC跟隨JDK1.4.2一起發(fā)布,并且Parallel GC在JDK6之后成為HotSpot默認(rèn)GC。

2. 不同 GC 的區(qū)別

HotSpot有這么多的垃圾回收器,那么如果有人問,Serial GC、Parallel GC、Concurrent Mark Sweep GC這三個GC有什么不同呢?請記住以下口令:

如果你想要最小化地使用內(nèi)存和并行開銷,請選Serial GC;
如果你想要最大化應(yīng)用程序的吞吐量,請選Parallel GC;
如果你想要最小化GC的中斷或停頓時間,請選CMS GC。

當(dāng)然這不包括新推出的 GC 方案----G1。

3. 關(guān)于 Java 1.7 之后的 G1

為什么名字叫做Garbage First(G1)呢?

因為G1是一個并行回收器,它把堆內(nèi)存分割為很多不相關(guān)的區(qū)間(Region),每個區(qū)間可以屬于老年代或者年輕代,并且每個年齡代區(qū)間可以是物理上不連續(xù)的。

老年代區(qū)間這個設(shè)計理念本身是為了服務(wù)于并行后臺線程,這些線程的主要工作是尋找未被引用的對象。而這樣就會產(chǎn)生一種現(xiàn)象,即某些區(qū)間的垃圾(未被引用對象)多于其他的區(qū)間。

垃圾回收時實則都是需要停下應(yīng)用程序的,不然就沒有辦法防治應(yīng)用程序的干擾 ,然后G1 GC可以集中精力在垃圾最多的區(qū)間上,并且只會費一點點時間就可以清空這些區(qū)間里的垃圾,騰出完全空閑的區(qū)間。

繞來繞去終于明白了,由于這種方式的側(cè)重點在于處理垃圾最多的區(qū)間,所以我們給G1一個名字:垃圾優(yōu)先(Garbage First)。

4. GC 的原理 1. 對象存活判斷

判斷對象是否存活一般有兩種方式:

引用計數(shù):每個對象有一個引用計數(shù)屬性,新增一個引用時計數(shù)加1,引用釋放時計數(shù)減1,計數(shù)為0時可以回收。此方法簡單,無法解決對象相互循環(huán)引用的問題。

可達(dá)性分析(Reachability Analysis):從GC Roots開始向下搜索,搜索所走過的路徑稱為引用鏈。當(dāng)一個對象到GC Roots沒有任何引用鏈相連時,則證明此對象是不可用的。不可達(dá)對象。

在Java語言中,GC Roots包括:虛擬機(jī)棧中引用的對象、方法區(qū)中類靜態(tài)屬性實體引用的對象、方法區(qū)中常量引用的對象、本地方法棧中JNI引用的對象。

2. GC 常用的算法及原理

引用計數(shù)法 (Reference Counting)

引用計數(shù)器在微軟的 COM 組件技術(shù)中、Adobe 的 ActionScript3 種都有使用。
引用計數(shù)器的實現(xiàn)很簡單,對于一個對象 A,只要有任何一個對象引用了 A,則 A 的引用計數(shù)器就加 1,當(dāng)引用失效時,引用計數(shù)器就減 1。只要對象 A 的引用計數(shù)器的值為 0,則對象 A 就不可能再被使用。
引用計數(shù)器的實現(xiàn)也非常簡單,只需要為每個對象配置一個整形的計數(shù)器即可。但是引用計數(shù)器有一個嚴(yán)重的問題,即無法處理循環(huán)引用(即兩個對象相互引用)的情況。因此,在 Java 的垃圾回收器中沒有使用這種算法。
一個簡單的循環(huán)引用問題描述如下:有對象 A 和對象 B,對象 A 中含有對象 B 的引用,對象 B 中含有對象 A 的引用。此時,對象 A 和對象 B 的引用計數(shù)器都不為 0。但是在系統(tǒng)中卻不存在任何第 3 個對象引用了 A 或 B。也就是說,A 和 B 是應(yīng)該被回收的垃圾對象,但由于垃圾對象間相互引用,從而使垃圾回收器無法識別,引起內(nèi)存泄漏。

標(biāo)記-清除算法 (Mark-Sweep)

標(biāo)記-清除算法將垃圾回收分為兩個階段:標(biāo)記階段和清除階段。一種可行的實現(xiàn)是,在標(biāo)記階段首先通過根節(jié)點,標(biāo)記所有從根節(jié)點開始的較大對象。因此,未被標(biāo)記的對象就是未被引用的垃圾對象。然后,在清除階段,清除所有未被標(biāo)記的對象。該算法最大的問題是存在大量的空間碎片,因為回收后的空間是不連續(xù)的。在對象的堆空間分配過程中,尤其是大對象的內(nèi)存分配,不連續(xù)的內(nèi)存空間的工作效率要低于連續(xù)的空間。

復(fù)制算法 (Copying)

將現(xiàn)有的內(nèi)存空間分為兩快,每次只使用其中一塊,在垃圾回收時將正在使用的內(nèi)存中的存活對象復(fù)制到未被使用的內(nèi)存塊中,之后,清除正在使用的內(nèi)存塊中的所有對象,交換兩個內(nèi)存的角色,完成垃圾回收。
如果系統(tǒng)中的垃圾對象很多,復(fù)制算法需要復(fù)制的存活對象數(shù)量并不會太大。因此在真正需要垃圾回收的時刻,復(fù)制算法的效率是很高的。又由于對象在垃圾回收過程中統(tǒng)一被復(fù)制到新的內(nèi)存空間中,因此,可確保回收后的內(nèi)存空間是沒有碎片的。該算法的缺點是將系統(tǒng)內(nèi)存折半。
Java 的新生代串行垃圾回收器中使用了復(fù)制算法的思想。新生代分為 eden 空間、from 空間、to 空間 3 個部分。其中 from 空間和 to 空間可以視為用于復(fù)制的兩塊大小相同、地位相等,且可進(jìn)行角色互換的空間塊。from 和 to 空間也稱為 survivor 空間,即幸存者空間,用于存放未被回收的對象。
在垃圾回收時,eden 空間中的存活對象會被復(fù)制到未使用的 survivor 空間中 (假設(shè)是 to),正在使用的 survivor 空間 (假設(shè)是 from) 中的年輕對象也會被復(fù)制到 to 空間中 (大對象,或者老年對象會直接進(jìn)入老年帶,如果 to 空間已滿,則對象也會直接進(jìn)入老年代)。此時,eden 空間和 from 空間中的剩余對象就是垃圾對象,可以直接清空,to 空間則存放此次回收后的存活對象。這種改進(jìn)的復(fù)制算法既保證了空間的連續(xù)性,又避免了大量的內(nèi)存空間浪費。

標(biāo)記-壓縮算法 (Mark-Compact)

復(fù)制算法的高效性是建立在存活對象少、垃圾對象多的前提下的。這種情況在年輕代經(jīng)常發(fā)生,但是在老年代更常見的情況是大部分對象都是存活對象。如果依然使用復(fù)制算法,由于存活的對象較多,復(fù)制的成本也將很高。
標(biāo)記-壓縮算法是一種老年代的回收算法,它在標(biāo)記-清除算法的基礎(chǔ)上做了一些優(yōu)化。也首先需要從根節(jié)點開始對所有可達(dá)對象做一次標(biāo)記,但之后,它并不簡單地清理未標(biāo)記的對象,而是將所有的存活對象壓縮到內(nèi)存的一端。之后,清理邊界外所有的空間。這種方法既避免了碎片的產(chǎn)生,又不需要兩塊相同的內(nèi)存空間,因此,其性價比比較高。

增量算法 (Incremental Collecting)

在垃圾回收過程中,應(yīng)用軟件將處于一種 CPU 消耗很高的狀態(tài)。在這種 CPU 消耗很高的狀態(tài)下,應(yīng)用程序所有的線程都會掛起,暫停一切正常的工作,等待垃圾回收的完成。如果垃圾回收時間過長,應(yīng)用程序會被掛起很久,將嚴(yán)重影響用戶體驗或者系統(tǒng)的穩(wěn)定性。
增量算法的基本思想是,如果一次性將所有的垃圾進(jìn)行處理,需要造成系統(tǒng)長時間的停頓,那么就可以讓垃圾收集線程和應(yīng)用程序線程交替執(zhí)行。每次,垃圾收集線程只收集一小片區(qū)域的內(nèi)存空間,接著切換到應(yīng)用程序線程。依次反復(fù),直到垃圾收集完成。使用這種方式,由于在垃圾回收過程中,間斷性地還執(zhí)行了應(yīng)用程序代碼,所以能減少系統(tǒng)的停頓時間。但是,因為線程切換和上下文轉(zhuǎn)換的消耗,會使得垃圾回收的總體成本上升,造成系統(tǒng)吞吐量的下降。

分代 (Generational Collecting)

根據(jù)垃圾回收對象的特性,不同階段最優(yōu)的方式是使用合適的算法用于本階段的垃圾回收,分代算法即是基于這種思想,它將內(nèi)存區(qū)間根據(jù)對象的特點分成幾塊,根據(jù)每塊內(nèi)存區(qū)間的特點,使用不同的回收算法,以提高垃圾回收的效率。以 Hot Spot 虛擬機(jī)為例,它將所有的新建對象都放入稱為年輕代的內(nèi)存區(qū)域,年輕代的特點是對象會很快回收,因此,在年輕代就選擇效率較高的復(fù)制算法。當(dāng)一個對象經(jīng)過幾次回收后依然存活,對象就會被放入稱為老生代的內(nèi)存空間。在老生代中,幾乎所有的對象都是經(jīng)過幾次垃圾回收后依然得以幸存的。因此,可以認(rèn)為這些對象在一段時期內(nèi),甚至在應(yīng)用程序的整個生命周期中,將是常駐內(nèi)存的。如果依然使用復(fù)制算法回收老生代,將需要復(fù)制大量對象。再加上老生代的回收性價比也要低于新生代,因此這種做法也是不可取的。根據(jù)分代的思想,可以對老年代的回收使用與新生代不同的標(biāo)記-壓縮算法,以提高垃圾回收效率。

5. 以 分代(Generational Collecting) 算法為例,說明 GC 機(jī)制

詞匯匯總:

Young generation :新生代
Eden : 伊甸園 (每個新 New 出來的對象最開始存放的位置)
Survivor : 幸存區(qū)(圖中S0與S1)
Tenured / Old Generation :老年代
Permanent Generation :永久代

注意: S0 與 S1 的內(nèi)存區(qū)域是一樣大的

下面講述其 GC 過程:

Step 1:
新創(chuàng)建的對象一般放在新生代的Eden區(qū)。
在 Eden 中有 “存活對象” 與 “待回收對象”,當(dāng)Eden空間被使用完的時候,就會發(fā)生新生代GC,也就是Minor GC。

Step 2:
GC 會做如何操作:

把 “存活對象” 復(fù)制到S0中。

清空 Eden 區(qū)。

將 S0 中的 “存活對象” 年齡(Age)設(shè)置為 1。

這樣第一次GC就完成了。
Step 3:
當(dāng)Eden區(qū)再次被使用完的時候,就會再次進(jìn)行GC操作。
GC 的操作如下:

將 Eden 區(qū)和 S0 中的“存活對象” 復(fù)制 到S1中。

清空 Eden 和 S0 區(qū)。

然后將 Eden 中復(fù)制到 S1 中的對象年齡設(shè)置為 1,將 S0 中復(fù)制到 S1 中的對象年齡加 1。

這樣新生代第二次GC就完成了。

Step 4:

當(dāng)Eden再一次被使用完的時候,就會發(fā)生第三次GC操作了。
之后基本重復(fù)上面的思路了,
GC 操作如下:

首先將 Eden 和 S1 中的 “存活對象” 復(fù)制到 S0 中。

然后將 Eden 和 S1 進(jìn)行清空。

最后將 Eden 中復(fù)制到 S0 中的對象年齡設(shè)置為1,將 S1 中復(fù)制到 S0 中的對象年齡加1。

之后就這樣循環(huán)了~~~

那 老年代 呢? 何時才會進(jìn)入 老年代 ?
如果對象在 GC 過程中沒有被回收,那么它的對象年齡(Age)會不斷的增加,對象在Survivor區(qū)每熬過一個Minor GC,年齡就增加1歲,當(dāng)它的年齡到達(dá)一定的程度(默認(rèn)為15歲),就會被移動到老年代,這個年齡閥值可以通過-XX:MaxTenuringThreshold設(shè)置。

6. 參考文章

這些文章或者視頻資料都很不錯,建議有興趣可以看看。

JVM 垃圾回收器工作原理及使用實例介紹
Java GC系列(2):Java垃圾回收是如何工作的?
YouTube 視頻:Garbage collection in Java, with Animation and discussion of G1 GC
Java GC系列(1):Java垃圾回收簡介
JVM內(nèi)存回收理論與實現(xiàn)
JVM為什么需要GC

7. 結(jié)束

這些是整理的筆記,希望對你有幫助。

沒有GC機(jī)制的JVM是不能想象的,我們只能通過不斷優(yōu)化它的使用、不斷調(diào)整自己的應(yīng)用程序,避免出現(xiàn)大量垃圾,而不是一味認(rèn)為GC造成了應(yīng)用程序問題。

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

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

相關(guān)文章

  • 細(xì)述 Java垃圾回收機(jī)制→How Java Garbage Collection Works?

    摘要:當(dāng)一個實例被創(chuàng)建的時候,它最初被存放在堆內(nèi)存空間的年輕代的區(qū)中。老年代或者永久代是堆內(nèi)存的第二個邏輯部分。在垃圾回收過程中掃描屬于部分的堆內(nèi)存。一旦實例從堆內(nèi)存中刪除了,它們原來的位置將空出來給以后分配實例使用。 本文非原創(chuàng),翻譯自How Java Garbage Collection Works?在Java中為對象分配和釋放內(nèi)存空間都是由垃圾回收線程自動執(zhí)行完成的。和C語言不一樣的是...

    cc17 評論0 收藏0
  • 垃圾回收算法與 JVM 垃圾回收器綜述

    摘要:垃圾回收算法與垃圾回收器綜述我們常說的垃圾回收算法可以分為兩部分對象的查找算法與真正的回收方法。串行垃圾回收器一次只使用一個線程進(jìn)行垃圾回收并行垃圾回收器一次將開啟多個線程同時進(jìn)行垃圾回收。 垃圾回收算法與 JVM 垃圾回收器綜述歸納于筆者的 JVM 內(nèi)部原理與性能調(diào)優(yōu)系列文章,文中涉及的引用資料參考 Java 學(xué)習(xí)與實踐資料索引、JVM 資料索引。 showImg(https://s...

    imingyu 評論0 收藏0
  • Java性能優(yōu)化之垃圾回收機(jī)制

    摘要:年輕代的目標(biāo)就是盡可能快速的收集掉那些生命周期短的對象。年老代在年輕代中經(jīng)歷了次垃圾回收后仍然存活的對象,就會被放到年老代中。什么情況下觸發(fā)垃圾回收由于對象進(jìn)行了分代處理,因此垃圾回收區(qū)域時間也不一樣。 [TOC] 與C/C++相比,java語言不需要程序員直接控制內(nèi)存回收,java程序的內(nèi)存分配和回收都是由JRE在后臺自動進(jìn)行,JRE會負(fù)責(zé)回收那些不再使用的內(nèi)存,這種機(jī)制被稱為垃圾...

    philadelphia 評論0 收藏0
  • 談一談JVM垃圾回收

    摘要:這個算法看似不錯而且簡單,不過存在這一個致命傷當(dāng)兩個對象互相引用的時候,就永遠(yuǎn)不會被回收于是引用計數(shù)算法就永遠(yuǎn)回收不了這兩個對象,下面介紹另一種算法。 前言 ? 如果要問Java與其他編程語言最大的不同是什么,我第一個想到的一定就是Java所運行的JVM所自帶的自動垃圾回收機(jī)制,以下是我學(xué)習(xí)JVM垃圾回收機(jī)制整理的筆記,希望能對讀者有一些幫助。 哪些內(nèi)存需要回收?what? ? ...

    stormzhang 評論0 收藏0
  • 《深入理解Java虛擬機(jī)》(三)垃圾收集器與內(nèi)存分配策略

    摘要:當(dāng)兩個對象相互引用時,這兩個對象就不會被回收引用計數(shù)算法不被主流虛擬機(jī)采用,主要原因是它很難解決對象之間相互循環(huán)引用的問題。 垃圾收集器與內(nèi)存分配策略 詳解 3.1 概述 本文參考的是周志明的 《深入理解Java虛擬機(jī)》第三章 ,為了整理思路,簡單記錄一下,方便后期查閱。 3.2 對象已死嗎 在垃圾收集器進(jìn)行回收前,第一件事就是確定這些對象哪些還存活,哪些已經(jīng)死去。 3.2.1 引用...

    Edison 評論0 收藏0

發(fā)表評論

0條評論

haoguo

|高級講師

TA的文章

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