wordpress dux 5.3關(guān)鍵詞推廣優(yōu)化app
二、垃圾回收GC
在堆里面存放著java的所有對象實例,當(dāng)對象為“死去”,也就是不再使用的對象,就會進(jìn)行垃圾回收GC
1.如何判斷對象可以回收
1.1引用計數(shù)器
介紹
在對象中添加一個引用計數(shù)器,當(dāng)一個對象被其他變量引用時這個對象的引用計數(shù)器加1。當(dāng)某個變量不再引用這個對象時引用計數(shù)器減1。當(dāng)這個引用計數(shù)變?yōu)?時,這個對象就會被垃圾回收。
優(yōu)點
判定效率很高
缺點
不完全準(zhǔn)確,當(dāng)兩個對象相互引用就判斷失效了。當(dāng)A引用B對象,B引用A對象,然后A和B不再被其他變量引用,垃圾不會回收,出現(xiàn)了垃圾回收失效。
1.2可達(dá)性分析算法(Java)
介紹
①要確定一個根對象GC Roots(肯定不會被垃圾回收的對象)作為起始節(jié)點,當(dāng)垃圾回收前會對堆對象進(jìn)行掃描,判斷這些對象是否被根對象引用,如果沒有被引用那么這個對象就可以垃圾回收。
②java虛擬機是通過可達(dá)性分析判斷存活對象
哪些對象可以作為GC Root?
①虛擬機棧中引用的對象
各個線程調(diào)用的方法(參數(shù),局部變量)
②本地方法棧中native方法引用的對象
③方法區(qū)中類靜態(tài)屬性引用的對象
Java類的引用類型靜態(tài)變量
④方法區(qū)中常量引用的對象
字符串常量池StringTable里的引用
⑤所有被同步鎖synchronized持有的對象
⑥java虛擬機內(nèi)部的引用,核心類
1.3四種引用
1.強引用-不回收
介紹
程序代碼中普遍存在的引用賦值“Object obj = new Object()”這種引用關(guān)系。
特點
不回收,只要沿著GC Root引用鏈能夠找到這個對象,這個對象就不會被垃圾回收。
2.軟引用-內(nèi)存不足回收
介紹
軟引用(間接引用)是一些還有用但非必需的對象,當(dāng)被軟引用關(guān)聯(lián)的對象,系統(tǒng)發(fā)生內(nèi)存溢出錢,會把這些對象列進(jìn)回收范圍進(jìn)行二次回收。如果這次回收沒有足夠的內(nèi)存,會拋出內(nèi)存溢出異常
特點
當(dāng)垃圾回收后,此時內(nèi)存仍不夠,軟引用關(guān)聯(lián)的對象會進(jìn)行垃圾回收(內(nèi)存不夠才回收)
3.弱引用-發(fā)現(xiàn)就回收
介紹
弱引用是一些還有用但非必需的對象,生存到下一次垃圾回收為止。在系統(tǒng)進(jìn)行垃圾回收時,發(fā)現(xiàn)弱引用,不管系統(tǒng)堆空間是否充足,都會回收軟引用關(guān)聯(lián)的對象。
特點
當(dāng)發(fā)生垃圾回收時,弱引用關(guān)聯(lián)的對象都會被回收。(內(nèi)存不管夠不夠都回收)
4.虛引用-對象回收跟蹤
介紹
當(dāng)虛引用對象創(chuàng)建時會關(guān)聯(lián)一個引用隊列。虛引用在創(chuàng)建時必須提供引用隊列作為參數(shù)。當(dāng)垃圾回收準(zhǔn)備回收一個對象時,如果發(fā)現(xiàn)他是虛引用,在垃圾回收后把這個虛引用加入引用隊列,通知應(yīng)用程序?qū)ο蟮幕厥涨闆r。
5.終結(jié)器引用-引用隊列配合
介紹
用于實現(xiàn)對象的finalize()方法。當(dāng)終結(jié)器對象創(chuàng)建時會關(guān)聯(lián)一個引用隊列。當(dāng)準(zhǔn)備回收一個對象時,發(fā)現(xiàn)是終結(jié)器引用,會把終結(jié)器引用對象放入引用隊列(此時對象沒回收)。由Finalizer線程調(diào)用該對象的finalize()方法,第二次垃圾回收就會回收此對象。
2.垃圾回收算法
2.1標(biāo)記清除
什么時候垃圾回收
掃描整個堆對象的過程中,如果發(fā)現(xiàn)對象被GC Root引用了,需要保留。如果這個對象沒有被GC Root引用,就要進(jìn)行垃圾回收。
標(biāo)記清除算法的兩個階段
①把沒有引用的對象標(biāo)記為垃圾。
②把垃圾對象占用的空間釋放,清除
③釋放不是空間清0,而是把起始地址記錄下來,然后將來把創(chuàng)建的新對象存儲這個位置
優(yōu)點
垃圾回收速度快
缺點
產(chǎn)生內(nèi)存碎片
2.2標(biāo)記整理
標(biāo)記整理兩個階段
①把沒有引用的對象標(biāo)記為垃圾
②把可用的對象向前移動,讓內(nèi)存更加緊湊。連續(xù)的空間變多。
優(yōu)點
沒有內(nèi)存碎片
缺點
對象整理過程中需要移動,垃圾回收效率低。
2.3復(fù)制
復(fù)制兩個階段
①把沒有引用的對象標(biāo)記為垃圾
②把活著的內(nèi)存分為兩塊from區(qū)和to區(qū)。把from區(qū)存活的對象復(fù)制到to區(qū)。然后清空from區(qū),然后交換from和to的位置
優(yōu)點
沒有內(nèi)存碎片
缺點
占用雙倍內(nèi)存空間
3.分代垃圾回收
介紹
垃圾回收時,JVM結(jié)合3種算法協(xié)程工作。通過分代的垃圾回收機制,把堆內(nèi)存劃分為2塊新生代和老年代,新生代(對象用完丟棄)劃分為3個區(qū)域:伊甸園,幸存區(qū)From,幸存區(qū)To。
老年代(對象長時間使用) 不同的區(qū)域,算法不同。
?
工作機制
①創(chuàng)建新的對象占用伊甸園的內(nèi)存空間,當(dāng)伊甸園內(nèi)存滿時,觸發(fā)垃圾回收Minor GC。沿著GC Roots引用鏈去找,如果對象沒有被引用,就進(jìn)行垃圾標(biāo)記。然后采用復(fù)制的算法把伊甸園存活的對象復(fù)制到幸存區(qū)To中,并且對象壽命加1。然后交換from和to的位置。
?②當(dāng)伊甸園內(nèi)存空間再次溢出時,觸發(fā)第二次垃圾回收Minor GC。沿著GC Roots根引用鏈進(jìn)行掃描伊甸園和幸存區(qū)。把存活的對象復(fù)制到幸存區(qū)To中,并且對象壽命加1。然后交換from和to的位置。
?③幸存區(qū)的對象壽命超過了閾值15,對象利用率高。晉升到老年代。(對象長時間使用)
?④當(dāng)新生代和老年代內(nèi)存要溢出時,觸發(fā)Full GC垃圾回收。
總結(jié)
①對象首先分配在伊甸園區(qū)域
②新生代空間不足時,觸發(fā)Minor gc。伊甸園和from存活的對象,使用復(fù)制算法copy到to中。存活的對象年齡加1.交換from和to。
③minor gc會引發(fā)stop the world暫停其他用戶的線程。垃圾回收結(jié)束,用戶恢復(fù)運行。
④當(dāng)對象壽命超過閾值時,會晉升到老年代,最大壽命是15
⑤老年代空間不足,觸發(fā)Minor gc內(nèi)存仍不足,那么full gc.
相關(guān)JVM參數(shù)
4.垃圾回收器
4.1串行垃圾回收器
介紹
①單線程垃圾回收器
②堆內(nèi)存較小,適合個人電腦
③開啟串行垃圾回收器 -XX:+UseSerialGC = Serial + SerialOld
Serial工作新生代,復(fù)制算法
SerialOld 工作在老年代,標(biāo)記整理算法
工作流程
當(dāng)堆內(nèi)存要溢出時,觸發(fā)垃圾回收。讓其他線程在安全點停止下來,等待垃圾回收線程的結(jié)束。
?
4.2吞吐量優(yōu)先:并行
介紹
①多線程
②堆內(nèi)存較大,多核cpu支持
③讓單位時間內(nèi),STW時間最短
工作流程
多核CPU中,有4個線程運行。當(dāng)堆內(nèi)存要溢出時,觸發(fā)了垃圾回收。用戶線程在安全點停止。此時的垃圾回收器會開啟多個線程(跟CPU核數(shù)相關(guān))進(jìn)行垃圾回收。然后恢復(fù)其他線程的運行。
相關(guān)參數(shù)
-XX:+UseParallelGC ~ -XX:+UseParallelOldGC ?開啟吞吐量優(yōu)先垃圾回收器
-XX:+UseAdaptiveSizePolicy ?自適應(yīng)大小策略,新生代
-XX:GCTimeRatio=ratio ?調(diào)整吞吐量
-XX:MaxGCPauseMillis=ms 最大暫停毫秒數(shù)
-XX:ParallelGCThreads=n 運行時線程數(shù)
4.3響應(yīng)時間優(yōu)先
介紹
①多線程
②堆內(nèi)存交大,多核cpu支持
③盡可能讓單次STW時間變短
相關(guān)參數(shù)
-XX:+UseConcMarkSweepGC~-XX:+UseParNewGC~SerialOld 開啟響應(yīng)時間優(yōu)先回收器
-XX:ParallelGCThreads=n~-XX:ConcGCThreads=threads 線程數(shù)
-XX:CMSInitiatingOccupancyFraction=percent 何時進(jìn)行垃圾回收
-XX:+CMSScavengeBeforeRemark 新生代垃圾回收
工作流程
當(dāng)老年代發(fā)生內(nèi)存泄漏,其他線程到達(dá)安全點暫停下來,垃圾回收器執(zhí)行初始標(biāo)記,用戶線程恢復(fù)運行。垃圾回收線程進(jìn)行并發(fā)標(biāo)記,然后進(jìn)行重新標(biāo)記工作。垃圾回收線程進(jìn)行并發(fā)清理。
5.G1垃圾回收器
簡介
Garbage First
JDK 9默認(rèn)
適用場景
①同時注重吞吐量和低延遲,默認(rèn)暫停目標(biāo)是200ms
②超大堆內(nèi)存,會將堆劃分多個大小相等的Region
③整體上是標(biāo)記+整理算法,兩個區(qū)域之間是復(fù)制算法。
相關(guān)JVM參數(shù)
-XX:+UseG1GC 開啟G1垃圾回收
-XX:G1HeapRegisonSize=size 設(shè)置劃分區(qū)域的大小
-XX:MaxGCPauseMills=time JVM最大暫停時間的目標(biāo)值
5.1 G1垃圾回收階段
1.Young Collection 新生代垃圾收集
①、G1會把堆內(nèi)存劃分成多個相等的區(qū)域。每個區(qū)域獨立作為伊甸園,幸存區(qū),老年代
②、新創(chuàng)建的對象會存儲在伊甸園,當(dāng)伊甸園內(nèi)存滿時會觸發(fā)新生代垃圾回收機制,會STW。
③、伊甸園存活的對象使用copy算法到幸存區(qū)。
④、當(dāng)幸存區(qū)的內(nèi)存溢出時,觸發(fā)新生代垃圾回收。幸存區(qū)對象存活年齡超過一定時間會晉升到老年代
2. Young Collection+Concurrent Mark新生代垃圾收集+并發(fā)標(biāo)記
①在Young GC時進(jìn)行GC Root的初始標(biāo)記
②老年代占用堆空間比例達(dá)到閾值時,進(jìn)行并發(fā)標(biāo)記(不會STW)
-XX:InitiatingHeapOccupancyPercent=percent(默認(rèn)45%)
3.Mixed Collection混合收集
介紹
會對E、S、O進(jìn)行全面垃圾回收
①最終標(biāo)記會STW
②拷貝存活會STW
-XX:MaxGCPauseMillis=ms
E:伊甸園區(qū)的存活對象通過復(fù)制算法到幸存區(qū)中
S:幸存區(qū)存活的對象復(fù)制到另一個幸存區(qū),符合晉升條件的到老年區(qū)
O:老年代區(qū)把存活對象復(fù)制到另一個老年代區(qū)
優(yōu)先收集垃圾最多的區(qū),目的是達(dá)到暫停時間段的目標(biāo)
5.2 Full GC?????
1.SerialGC
①新生代內(nèi)存不足發(fā)生的垃圾收集—minor gc
②老年代內(nèi)存不足發(fā)生的垃圾收集—full gc
2.ParallelGC
①新生代內(nèi)存不足發(fā)生的垃圾收集—minor gc
②老年代內(nèi)存不足發(fā)生的垃圾收集—full gc
3.CMS
①新生代內(nèi)存不足發(fā)生的垃圾收集—minor gc
②老年代內(nèi)存不足,并發(fā)失敗后才會full gc。
4.G1
①新生代內(nèi)存不足發(fā)生的垃圾收集—minor gc
②老年代內(nèi)存不足,老年代內(nèi)存跟堆內(nèi)存占比達(dá)到45%,觸發(fā)并發(fā)標(biāo)記和混合收集階段?;厥账俣?gt;垃圾產(chǎn)生速度,并發(fā)垃圾收集階段?;厥账俣?lt;垃圾產(chǎn)生速度,此時是full gc
5.3Young Collection跨代引用
1.新生代回收的跨代引用(老年代引用新生代)
①根對象有部分是來自老年代,老年代存活對象比較多,遍歷效率低。所以采用CardTable把老年代區(qū)域進(jìn)行細(xì)分成一個個的card。每個card是512k。如果老年代的對象引用了新生代的對象,就會把這個card標(biāo)記為臟卡。只關(guān)注臟卡,減少搜索范圍。
?②臟卡引用了新生代的對象。新生代通過Remembered Set知道對應(yīng)的臟卡。通過臟卡區(qū)域遍歷GC Roots
5.4 Remark-重新標(biāo)記
并發(fā)標(biāo)記階段的對象處理狀態(tài)
?
黑色已經(jīng)處理完成,存活的對象?;疑翘幚懋?dāng)中的。白色是尚未處理的垃圾。
在并發(fā)標(biāo)記階段可能出現(xiàn)B對C引用,接著斷開后C成為垃圾,然后A對C引用。此時C被判成垃圾了。
這個時候需要用到remark
Remark:對對象進(jìn)行進(jìn)一步檢查,當(dāng)對象引用發(fā)生改變時,會給引用提供一個寫屏障(將C加入隊列),接著進(jìn)入重新標(biāo)記階段,對隊列對象進(jìn)行檢查,有強引用的不標(biāo)記為垃圾。
5.5 JDK8 u20字符串去重
指令
-XX:+UseStringDeduplication
規(guī)則
①將所有新分配的字符串放入一個隊列
②當(dāng)新生代回收時,G1并發(fā)檢查是否有字符串重復(fù)
③如果值一樣,讓他們引用同一個char[]
優(yōu)缺點
優(yōu)點:節(jié)約大量內(nèi)存
缺點:多占用CPU時間,新時代回收時間略微增加
跟String.intern()不一樣
①String.intern()關(guān)注的是字符串對象
②字符串去重關(guān)注的是char[]
③JVM內(nèi)部使用不同的字符串表
5.6 JDK8 u40并發(fā)標(biāo)記類卸載
所有對象都經(jīng)過并發(fā)標(biāo)記后,知道哪些類不再使用。當(dāng)一個類加載器所有類不再使用,則卸載它所加載的所有類
-xx:+ClassUnloadingWithConcurrentMark默認(rèn)啟用
5.7 JDK8 u60 回收巨型對象
①一個對象大于region的一半時,成為巨型對象。
②G1不會對巨型對象進(jìn)行拷貝
③回收時優(yōu)先考慮
④G1會跟蹤老年代所有incoming引用。這樣老年代incoming引用為0的巨型對象在新生代垃圾回收處理掉。
5.8 JDK9 并發(fā)標(biāo)記起始時間的調(diào)整
①并發(fā)標(biāo)記必須在堆空間占滿前完成,否則退化為FullGC
②JDK 9之前需要使用 -XX:InitiatingHeapOccupancyPercent
③JDK 9可以調(diào)整:
-XX:InitiatingHeapOccupancyPercent 用來設(shè)置初始值
進(jìn)行數(shù)據(jù)采樣并動態(tài)調(diào)整
總會添加一個安全的空擋空間