日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java GC原理简单讲解

發(fā)布時間:2023/12/19 java 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java GC原理简单讲解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

了解GC,首先需要了解jvm,之前寫過關(guān)于虛擬機(jī)的文章《Java虛擬機(jī)簡單介紹》

其次就是了解設(shè)置jvm內(nèi)存參數(shù)和設(shè)置方法,這也寫過文章《jvm 常用調(diào)試工具和設(shè)置jvm GC方法和指令》?PermSize 永久代 NewSize ?新生代 Xms Xmx 堆 Xss 棧

再者就是了解jvm中有幾種GC以及啟動方法,也有寫過文章《java 基礎(chǔ)知識部分提煉》;但是為什么jvm中有好幾款GC呢?你可以這樣思考:如果你是jvm的開發(fā)者,jvm中要嵌入自己的GC算法。你開發(fā)出來的jvm可能需要跑在單cpu的PC上,也有可能跑在多CPU集群的服務(wù)器上,也有可能被用來開發(fā)大型的應(yīng)用,也有可能被用來開發(fā)單線程的命令行程序等等。那么不同的平臺或者開發(fā)的軟件類別不能一概而論的使用同一款,或者同一種算法的GC。那么這樣太粗糙了!所以JVM中嵌入了幾款不同GC,用戶可以根據(jù)自己的需要強(qiáng)行設(shè)置自己的jvm GC方式。注意:安裝了jre,跑了好幾款不同的Java應(yīng)用,那么就對應(yīng)好幾個jvm,那么要指定JVM指配GC方式。

在pc上cmd中設(shè)置GC類型:


爆出沒有啟動的jvm,所以需要有運行的jvm,指定jvm設(shè)置GC類型。

在Tomcat 服務(wù)器上設(shè)置GC類型:?在tomcat的catalina.bat中設(shè)置啟動參數(shù)

  • set?JAVA_OPTS=-Xms10240m?-Xmx10240m?-Xmn3000m?-XX:PermSize=1024m?-XX:MaxPermSize=2048m?-XX:MaxNewSize=256m?-Xss1024K?-XX:-UseConcMarkSweepGC?-XX:+ScavengeBeforeFullGC??-XX:+PrintGC?-XX:+PrintGCTimeStamps?-Xloggc:"c:\gc_20121128.log" ?

  • -XX:+/- 解釋:-XX: 是設(shè)置jvm命令符,后面的加號或者減號是表示增加或者去掉的意思。


    今天的文章就是說說不同GC的工作大致原理。

    基本的GC回收算法:

    1. 引用計數(shù)(Reference Counting)?
    比較古老的回收算法。原理是此對象有一個引用,即增加一個計數(shù),刪除一個引用則減少一個計數(shù)。垃圾回收時,只用收集計數(shù)為0的對象。此算法最致命的是無法處理循環(huán)引用的問題。?
    2. 標(biāo)記-清除(Mark-Sweep)?
    此算法執(zhí)行分兩階段。第一階段從引用根節(jié)點開始標(biāo)記所有被引用的對象,第二階段遍歷整個堆,把未標(biāo)記的對象清除。此算法需要暫停整個應(yīng)用,同時,會產(chǎn)生內(nèi)存碎片。?
    3. 復(fù)制(Copying)?
    此算法把內(nèi)存空間劃為兩個相等的區(qū)域,每次只使用其中一個區(qū)域。垃圾回收時,遍歷當(dāng)前使用區(qū)域,把正在使用中的對象復(fù)制到另外一個區(qū)域中。次算法每次只處理正在使用中的對象,因此復(fù)制成本比較小,同時復(fù)制過去以后還能進(jìn)行相應(yīng)的內(nèi)存整理,不過出現(xiàn)“碎片”問題。當(dāng)然,此算法的缺點也是很明顯的,就是需要兩倍內(nèi)存空間。?
    4. 標(biāo)記-整理(Mark-Compact)?
    此算法結(jié)合了 “標(biāo)記-清除”和“復(fù)制”兩個算法的優(yōu)點。也是分兩階段,第一階段從根節(jié)點開始標(biāo)記所有被引用對象,第二階段遍歷整個堆,把清除未標(biāo)記對象并且把存活對象 “壓縮”到堆的其中一塊,按順序排放。此算法避免了“標(biāo)記-清除”的碎片問題,同時也避免了“復(fù)制”算法的空間問題。?
    5. 增量收集(Incremental Collecting)?
    實施垃圾回收算法,即:在應(yīng)用進(jìn)行的同時進(jìn)行垃圾回收。不知道什么原因JDK5.0中的收集器沒有使用這種算法的。?
    6. 分代(Generational Collecting)?


    基于對對象生命周期分析后得出的垃圾回收算法。把對象分為年青代、年老代、持久代,對不同生命周期的對象使用不同的算法(上述方式中的一個)進(jìn)行回收。現(xiàn)在的垃圾回收器(從J2SE1.2開始)都是使用此算法的。?

    1. Young(年輕代)?
    年輕代分三個區(qū)。一個Eden區(qū),兩個 Survivor區(qū)。大部分對象在Eden區(qū)中生成。當(dāng)Eden區(qū)滿時,還存活的對象將被復(fù)制到Survivor區(qū)(兩個中的一個),當(dāng)這個 Survivor區(qū)滿時,此區(qū)的存活對象將被復(fù)制到另外一個Survivor區(qū),當(dāng)這個Survivor去也滿了的時候,從第一個Survivor區(qū)復(fù)制過來的并且此時還存活的對象,將被復(fù)制“年老區(qū)(Tenured)”。需要注意,Survivor的兩個區(qū)是對稱的,沒先后關(guān)系,所以同一個區(qū)中可能同時存在從Eden復(fù)制過來對象,和從前一個Survivor復(fù)制過來的對象,而復(fù)制到年老區(qū)的只有從第一個Survivor去過來的對象。而且,Survivor區(qū)總有一個是空的。?
    2. Tenured(年老代)?
    年老代存放從年輕代存活的對象。一般來說年老代存放的都是生命期較長的對象。?
    3. Perm(持久代)?
    用于存放靜態(tài)文件,如今Java類、方法等。持久代對垃圾回收沒有顯著影響,但是有些應(yīng)用可能動態(tài)生成或者調(diào)用一些class,例如Hibernate等,在這種時候需要設(shè)置一個比較大的持久代空間來存放這些運行過程中新增的類。持久代大小通過-XX:MaxPermSize=<N>進(jìn)行設(shè)置。?

    試想,如果是你寫一個GC回收算法,你會思考怎么是實現(xiàn)呢?對于我,我認(rèn)為我肯定是和“標(biāo)記-清除”算法思維一樣。純粹的計數(shù)法太過于簡單,搞不好數(shù)據(jù)就清除掉了。那么為什么會和“標(biāo)記-清除”思維一樣呢?Java里面所有的類都是繼承于object,依次類推開發(fā)者每一次在內(nèi)存中創(chuàng)建對象都是在以object的為根節(jié)點的父節(jié)點上創(chuàng)建。那么整個內(nèi)存中所有的對象在數(shù)據(jù)關(guān)聯(lián)方面就是一個很大的樹結(jié)構(gòu)。唯一做到的就是記錄對象生存周期,那么只要記錄比較一個父節(jié)點不可到達(dá),或者聲明結(jié)束,那么下面的子樹結(jié)構(gòu)都標(biāo)記刪除。但是這樣做貌似在記錄上很復(fù)雜。當(dāng)然也可以在某一個子樹結(jié)構(gòu)執(zhí)行完,不可到達(dá)的時候,將樹的其他整體分支,copy出來,新建的整體樹相當(dāng)于砍去不可到達(dá)的結(jié)構(gòu)之后的大樹,每一次都發(fā)現(xiàn)有不可到達(dá)的就copy一次整體的樹形結(jié)構(gòu)。當(dāng)內(nèi)存不足的時候除了最后創(chuàng)建的整體樹結(jié)構(gòu)保留之外其他的都刪除。但是這樣貌似加大了內(nèi)存消耗,內(nèi)存消耗極快呀!你有好的思維發(fā)散嗎?


    對于不同的jvm(JVM種類多達(dá)幾十種),GC一般大同小異,下面介紹的幾種GC是傳統(tǒng)較為標(biāo)準(zhǔn)的OracleJVM -- hotspot VM垃圾回收器。要知道很多公司只做jvm,有的jvm支持iOS系統(tǒng),.net框架等(對的,有的jvm是針對支持iOS和.net)。針對不同平臺如android、pc、服務(wù)器等有不同種類的jvm。


    GC的種類:

    新生代的GC:

    新生代通常存活時間較短,因此基于Copying算法來進(jìn)行回收,所謂Copying算法就是掃描出存活的對象,并復(fù)制到一塊新的完全未使用的空間中,對應(yīng)于新生代,就是在Eden和FromSpace或ToSpace之間copy。新生代采用空閑指針的方式來控制GC觸發(fā),指針保持最后一個分配的對象在新生代區(qū)間的位置,當(dāng)有新的對象要分配內(nèi)存時,用于檢查空間是否足夠,不夠就觸發(fā)GC。當(dāng)連續(xù)分配對象時,對象會逐漸從eden到survivor,最后到舊生代,

    用javavisualVM來查看,能明顯觀察到新生代滿了后,會把對象轉(zhuǎn)移到舊生代,然后清空繼續(xù)裝載,當(dāng)舊生代也滿了后,就會報outofmemory的異常,如下圖所示:


    在執(zhí)行機(jī)制上JVM提供了串行GC(SerialGC)、并行回收GC(ParallelScavenge)和并行GC(ParNew)

    1)串行GC

    在整個掃描和復(fù)制過程采用單線程的方式來進(jìn)行,適用于單CPU、新生代空間較小及對暫停時間要求不是非常高的應(yīng)用上,是client級別默認(rèn)的GC方式,可以通過-XX:+UseSerialGC來強(qiáng)制指定

    2)并行回收GC

    在整個掃描和復(fù)制過程采用多線程的方式來進(jìn)行,適用于多CPU、對暫停時間要求較短的應(yīng)用上,是server級別默認(rèn)采用的GC方式,可用-XX:+UseParallelGC來強(qiáng)制指定,用-XX:ParallelGCThreads=4來指定線程數(shù)

    3)并行GC

    與舊生代的并發(fā)GC配合使用


    舊生代的GC:

    舊生代與新生代不同,對象存活的時間比較長,比較穩(wěn)定,因此采用標(biāo)記(Mark)算法來進(jìn)行回收,所謂標(biāo)記就是掃描出存活的對象,然后再進(jìn)行回收未被標(biāo)記的對象,回收后對用空出的空間要么進(jìn)行合并,要么標(biāo)記出來便于下次進(jìn)行分配,總之就是要減少內(nèi)存碎片帶來的效率損耗。在執(zhí)行機(jī)制上JVM提供了串行GC(SerialMSC)、并行GC(parallelMSC)和并發(fā)GC(CMS),具體算法細(xì)節(jié)還有待進(jìn)一步深入研究。


    ? ? ? ? ?

    ? ? ? ?G1回收器:

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

    2、分代收集:雖然G1可以不需要其他收集器配合就能獨立管理整個GC堆,但是還是保留了分代的概念。它能夠采用不同的方式去處理新創(chuàng)建的對象和已經(jīng)存活了一段時間,熬過多次GC的舊對象以獲取更好的收集效果。

    3、空間整合:與CMS的“標(biāo)記--清理”算法不同,G1從整體來看是基于“標(biāo)記整理”算法實現(xiàn)的收集器;從局部上來看是基于“復(fù)制”算法實現(xiàn)的。

    4、可預(yù)測的停頓:這是G1相對于CMS的另一個大優(yōu)勢,降低停頓時間是G1和CMS共同的關(guān)注點,但G1除了追求低停頓外,還能建立可預(yù)測的停頓時間模型,能讓使用者明確指定在一個長度為M毫秒的時間片段內(nèi),

    5、G1運作步驟:1、初始標(biāo)記;2、并發(fā)標(biāo)記;3、最終標(biāo)記;4、篩選回收


    總結(jié)

    以上是生活随笔為你收集整理的Java GC原理简单讲解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。