|
Concurrent Mark Sweep??疵志椭?,CMS是一款并發(fā)、使用標(biāo)記-清除算法的gc。CMS是針對老年代進(jìn)行回收的GC。 一、哪些對象可以回收1、引用計(jì)數(shù)法算法過程: 每個(gè)對象有一個(gè)引用計(jì)數(shù)器,當(dāng)對象被引用一次計(jì)數(shù)器就加一,引用失效就減一,對于計(jì)數(shù)器為0的對象表示為垃圾對象,可以被GC回收。 請分析以下哪些操作是原子性操作: 缺點(diǎn): 無法解決循環(huán)引用的問題,例如:A引用了B,B引用了A,但是A和B都沒有被其他對象引用,這樣就會導(dǎo)致內(nèi)存泄漏,無法被回收。 2、可達(dá)性分析法算法過程:通過一系列被稱為GC Roots的對象作為起點(diǎn)開始搜索,所經(jīng)過的路徑被稱為引用鏈,當(dāng)一個(gè)對象沒有跟任何一個(gè)引用鏈相連接的時(shí)候,表示從GC Roots對象到這個(gè)對象不可達(dá),意味著這是一個(gè)垃圾對象可以被回收。 適用場景:Java虛擬機(jī)是采用這種算法對垃圾進(jìn)行回收,解決了循環(huán)引用的問題。 可以作為GC Roots對象有:虛擬機(jī)棧,靜態(tài)成員,常量,本地方法棧引用的對象。 二、垃圾回收算法1、標(biāo)記清除算法過程:首先標(biāo)記出需要回收的對象,標(biāo)記完成后統(tǒng)一回收。 缺點(diǎn):主要有兩個(gè)缺點(diǎn),一個(gè)是標(biāo)記和清除兩個(gè)過程的效率都不算高(據(jù)資料顯示)。另一個(gè)是空間問題,標(biāo)記清除后,會產(chǎn)生不連續(xù)的內(nèi)存碎片,當(dāng)需要分配大對象時(shí),無法找到足夠連續(xù)的內(nèi)存,導(dǎo)致分配失敗提前觸發(fā)GC。 2、復(fù)制算法算法過程:將內(nèi)存分為兩部分,每次只使用其中一塊內(nèi)存?;厥諘r(shí)將存活的對象復(fù)制到另一塊區(qū)域,之后將已使用的內(nèi)存區(qū)域一次性全部清理掉。 優(yōu)點(diǎn):解決了空間碎片的問題,存活對象少時(shí),提升了回收效率。 缺點(diǎn):一個(gè)是內(nèi)存使用率縮小了,因?yàn)橛肋h(yuǎn)有一塊空閑的內(nèi)存?zhèn)溆?。另一個(gè)是當(dāng)存活對象較多時(shí)復(fù)制效率低下。 3、標(biāo)記整理算法過程:標(biāo)記整理的算法過程跟標(biāo)記清除的標(biāo)記過程是一樣的,但標(biāo)記后是將存活的對象都向某一端移動,然后清理邊界以外的內(nèi)存。 優(yōu)點(diǎn):解決了內(nèi)存碎片的問題。 可以作為GC Roots對象有:虛擬機(jī)棧,靜態(tài)成員,常量,本地方法棧引用的對象。 三、CMS介紹1、介紹老年代收集器,需要配合Serial或者ParNew使用,一般是與ParNew使用。CMS全稱Concurrent Mark-Sweep。CMS出現(xiàn)的目標(biāo)是為了降低延遲,減少回收停頓時(shí)間。適合對延遲、停頓時(shí)間敏感的應(yīng)用使用。通過 -XX:+UseConcMarkSweepGC開啟。 2、回收階段CMS-initial-mark(STW):通過可達(dá)性分析算法,從GC Roots對象開始掃描能夠直接關(guān)聯(lián)到的對象,并做標(biāo)記,需要STW,但是一般會很快完成。 CMS-concurrent-mark:從初始標(biāo)記的基礎(chǔ)上,繼續(xù)向下搜索并做標(biāo)記,這個(gè)階段應(yīng)用線程和GC線程并發(fā)執(zhí)行,不會造成停頓。 CMS-concurrent-preclean:查找并發(fā)標(biāo)記階段中,新進(jìn)入老年代的對象,包括晉升到老年代和直接在老年代分配的對象,目的是減少下一個(gè)階段重新標(biāo)記的時(shí)間。 CMS-concurrent-abortable-preclean:可中斷的預(yù)清理,這個(gè)階段做的事情跟并發(fā)預(yù)清理的事情一樣,目的是為了減少下一個(gè)階段STW的時(shí)間,這個(gè)階段有幾個(gè)個(gè)條件控制何時(shí)結(jié)束。 A、-XX:CMSScheduleRemarkEdenSizeThreshold=2.該階段在Eden區(qū)占用超過2M時(shí)啟動。 B、-XX:CMSMaxAbortablePrecleanTime=5000.設(shè)置一個(gè)最大時(shí)間最大執(zhí)行5秒鐘。 C、-XX:CMSScheduleRemarkEdenPenetration=50.Eden區(qū)使用率超過50就停止該階段進(jìn)入remark階段。 D、-XX:+CMSScavengeBeforeRemark,控制remark階段前進(jìn)行一次minor gc,來提高remark的效率,減少時(shí)間。 CMS-remark(STW):重新標(biāo)記,處理上幾次以來可能引用關(guān)系發(fā)生變化的部分,并重新進(jìn)行標(biāo)記,這個(gè)階段會停止應(yīng)用線程 CMS-concurrent-sweep:真正的清理階段,將以上幾個(gè)步驟標(biāo)記的無法訪問的對象進(jìn)行并發(fā)清理,并將清理的空間回收到空閑列表中 CMS-concurrent-reset:調(diào)整堆大小,重置一些內(nèi)部的數(shù)據(jù)結(jié)構(gòu),為下一次回收做準(zhǔn)備 3、缺點(diǎn)A、無法處理浮動垃圾,因?yàn)檫@是一款并發(fā)的收集器,程序運(yùn)行和收集的同時(shí)都會產(chǎn)生垃圾,所以回收時(shí)不能向其他收集器一樣等到滿了的時(shí)候再收集,通過-XX:CMSInitiatingOccupancyFraction=65設(shè)置觸發(fā)的百分比,留出一定的空間給并發(fā)收集的時(shí)候使用,當(dāng)CMS運(yùn)行期間無法滿足程序的需要,則會出現(xiàn),此時(shí)會臨時(shí)使用Serial Old作為臨時(shí)方案進(jìn)行一次標(biāo)記整理的回收,這樣就會使得出現(xiàn)較為長期的停頓,所以-XX:CMSInitiatingOccupancyFraction=65不能設(shè)置太高。 B、由于是使用標(biāo)記清除算法的收集器,因此會產(chǎn)生內(nèi)存碎片,為了解決這個(gè)問題,垃圾收集器提供了一個(gè)-XX:+UseCMSCompactAtFullCollection的開關(guān)參數(shù),表示再一次FGC時(shí)進(jìn)行一次內(nèi)存整理的過程,這個(gè)過程是無法并發(fā)的,會拉長停頓時(shí)間,收集器還提供另一個(gè)參數(shù),-XX:CMSFullGCsBeforeCompaction=5表示FGC幾次后進(jìn)行一次內(nèi)存整理。 4、優(yōu)化措施優(yōu)化目標(biāo):減少STW停頓時(shí)間 優(yōu)化手段: A、降低觸發(fā)CMS回收的百分比,給并發(fā)收集時(shí)留出一定的空間,避免Concurrent Mode Failure,通過-XX:CMSInitiatingOccupancyFraction=65配置 B、開啟內(nèi)存壓縮,避免碎片問題無法分配大內(nèi)存對象,通過-XX:+UseCMSCompactAtFullCollection和-XX:CMSFullGCsBeforeCompaction=5.具體數(shù)值可以按需調(diào)配。 C、減少CMS-remark(STW)階段的時(shí)間,通過-XX:+CMSScavengeBeforeRemark、-XX:CMSMaxAbortablePrecleanTime=5000、-XX:CMSScheduleRemarkEdenPenetration=50進(jìn)行微調(diào)。 5、相關(guān)參數(shù)
6、日志分析以下是一次完整的CMS回收日志,需要配置以下參數(shù) 2019-07-17T21:54:50.216+0800: 190007.616: [GC [1 CMS-initial-mark: 1258440K(2097152K)] 1294890K(3984640K), 0.0365050 secs] [Times: user=0.04 sys=0.01, real=0.04 secs]2019-07-17T21:54:50.253+0800: 190007.654: Total time for which application threads were stopped: 0.0455330 seconds2019-07-17T21:54:50.254+0800: 190007.654: [CMS-concurrent-mark-start]2019-07-17T21:54:50.413+0800: 190007.813: [CMS-concurrent-mark: 0.159/0.159 secs] [Times: user=0.91 sys=0.02, real=0.16 secs]2019-07-17T21:54:50.413+0800: 190007.814: [CMS-concurrent-preclean-start]2019-07-17T21:54:50.413+0800: 190007.814: [Preclean SoftReferences, 0.0005560 secs]2019-07-17T21:54:50.414+0800: 190007.814: [Preclean WeakReferences, 0.0011690 secs]2019-07-17T21:54:50.415+0800: 190007.815: [Preclean FinalReferences, 0.0000350 secs]2019-07-17T21:54:50.415+0800: 190007.815: [Preclean PhantomReferences, 0.0000070 secs]2019-07-17T21:54:50.425+0800: 190007.825: [CMS-concurrent-preclean: 0.011/0.011 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]2019-07-17T21:54:50.425+0800: 190007.826: [CMS-concurrent-abortable-preclean-start] CMS: abort preclean due to time 2019-07-17T21:54:51.938+0800: 190009.338: [CMS-concurrent-abortable-preclean: 1.508/1.512 secs] [Times: user=2.46 sys=0.16, real=1.51 secs]2019-07-17T21:54:51.938+0800: 190009.338: Application time: 1.6846120 seconds2019-07-17T21:54:51.946+0800: 190009.346: [GC[YG occupancy: 351451 K (1887488 K)]2019-07-17T21:54:51.946+0800: 190009.347: [GC2019-07-17T21:54:51.949+0800: 190009.350: [ParNew2019-07-17T21:54:51.979+0800: 190009.379: [SoftReference, 2284 refs, 0.0002550 secs]2019-07-17T21:54:51.979+0800: 190009.379: [WeakReference, 5 refs, 0.0000150 secs]2019-07-17T21:54:51.979+0800: 190009.379: [FinalReference, 679 refs, 0.0002280 secs]2019-07-17T21:54:51.979+0800: 190009.380: [PhantomReference, 0 refs, 0.0000120 secs]2019-07-17T21:54:51.979+0800: 190009.380: [JNI Weak Reference, 0.0000100 secs]: 351451K->23085K(1887488K), 0.0330260 secs] 1609892K->1282310K(3984640K), 0.0370030 secs] [Times: user=0.26 sys=0.01, real=0.04 secs]2019-07-17T21:54:51.984+0800: 190009.384: [Rescan (parallel) , 0.0272010 secs]2019-07-17T21:54:52.011+0800: 190009.411: [weak refs processing2019-07-17T21:54:52.011+0800: 190009.411: [SoftReference, 5341 refs, 0.0020150 secs]2019-07-17T21:54:52.013+0800: 190009.413: [WeakReference, 0 refs, 0.0000220 secs]2019-07-17T21:54:52.013+0800: 190009.413: [FinalReference, 80 refs, 0.0002020 secs]2019-07-17T21:54:52.013+0800: 190009.414: [PhantomReference, 0 refs, 0.0000120 secs]2019-07-17T21:54:52.013+0800: 190009.414: [JNI Weak Reference, 0.0000230 secs], 0.0023470 secs]2019-07-17T21:54:52.013+0800: 190009.414: [class unloading, 0.0198310 secs]2019-07-17T21:54:52.033+0800: 190009.434: [scrub symbol table, 0.0100610 secs]2019-07-17T21:54:52.043+0800: 190009.444: [scrub string table, 0.0011130 secs] [1 CMS-remark: 1259224K(2097152K)] 1282310K(3984640K), 0.1204410 secs] [Times: user=0.48 sys=0.02, real=0.12 secs]2019-07-17T21:54:52.067+0800: 190009.468: Total time for which application threads were stopped: 0.1293860 seconds2019-07-17T21:54:52.068+0800: 190009.468: [CMS-concurrent-sweep-start]2019-07-17T21:54:52.747+0800: 190010.147: [CMS-concurrent-sweep: 0.679/0.679 secs] [Times: user=1.24 sys=0.09, real=0.68 secs]2019-07-17T21:54:52.747+0800: 190010.147: [CMS-concurrent-reset-start]2019-07-17T21:54:52.753+0800: 190010.153: [CMS-concurrent-reset: 0.006/0.006 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]12345678910111213141516復(fù)制代碼類型:[java] 通用字段解析
CMS-initial-mark
CMS-concurrent-mark
CMS-concurrent-abortable-preclean
YG occupancy
CMS-remark
四、實(shí)戰(zhàn)1、測試代碼/**
* 堆溢出測試
* -Xms100m -Xmx100m -XX:+UseConcMarkSweepGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/dump.hprof
*
* @author Horace
*/public class HeapOOMTest {private static Logger logger = LoggerFactory.getLogger(HeapOOMTest.class);public static void main(String[] args) {int _1M = 1024 * 1024;
List<byte[]> bytes = new ArrayList<>();while (true) {
bytes.add(new byte[_1M]);
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1000));
}
}
}1234567891011121314151617復(fù)制代碼類型:[java]2、查看GC情況本地環(huán)境界面查看工具 jvisualvm 每1秒輸出一次GC情況 jstat -gccause pid 1s 以下是GC情況 S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC 89.83 0.00 42.05 37.10 94.37 90.41 2 0.025 0 0.000 0.025 Allocation Failure No GC 89.83 0.00 46.58 37.10 94.37 90.41 2 0.025 0 0.000 0.025 Allocation Failure No GC 89.83 0.00 51.00 37.10 94.37 90.41 2 0.025 0 0.000 0.025 Allocation Failure No GC 89.83 0.00 54.74 37.10 94.37 90.41 2 0.025 0 0.000 0.025 Allocation Failure No GC 89.83 0.00 58.49 37.10 94.37 90.41 2 0.025 0 0.000 0.025 Allocation Failure No GC 89.83 0.00 63.69 37.10 94.37 90.41 2 0.025 0 0.000 0.025 Allocation Failure No GC 89.83 0.00 67.44 37.10 94.37 90.41 2 0.025 0 0.000 0.025 Allocation Failure No GC 89.83 0.00 71.19 37.10 94.37 90.41 2 0.025 0 0.000 0.025 Allocation Failure No GC 89.83 0.00 75.71 37.10 94.37 90.41 2 0.025 0 0.000 0.025 Allocation Failure No GC 89.83 0.00 79.46 37.10 94.37 90.41 2 0.025 0 0.000 0.025 Allocation Failure No GC 89.83 0.00 83.98 37.10 94.37 90.41 2 0.025 0 0.000 0.025 Allocation Failure No GC 89.83 0.00 87.72 37.10 94.37 90.41 2 0.025 0 0.000 0.025 Allocation Failure No GC 89.83 0.00 92.14 37.10 94.37 90.41 2 0.025 0 0.000 0.025 Allocation Failure No GC1234567891011121314復(fù)制代碼類型:[java] 各個(gè)字段表示的含義可以查看: https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html#BEHHGFAE 命令行dump內(nèi)存快照 jmap -heap dump:live,format=b,file=/tmp/dump.hprof dump出來的內(nèi)存可以通過jprofile、mat、jhat等工具進(jìn)行分析 |
|
|