在沒(méi)有任何jvm參數(shù)配置的情況下,默認(rèn)System.gc會(huì)觸發(fā)一次full gc。針對(duì)cms gc的情況下,默認(rèn)其實(shí)執(zhí)行的是serial gc咧擂。
通過(guò)配置-XX:+ExplicitGCInvokesConcurrent 來(lái)避免執(zhí)行serial gc逞盆。
參考源代碼:
voidGenCollectedHeap::collect(GCCause::Causecause){
? if(should_do_concurrent_full_gc(cause)){
? ? ?#ifndefSERIALGC// mostly concurrent full
? ? ? ? collectioncollect_mostly_concurrent(cause);
? ? ?#else// SERIALGC
? ? ? ? ShouldNotReachHere();
? ? ?#endif// SERIALGC
? }else{
? ? #ifdefASSERT
? ? ? ? if(cause==GCCause::_scavenge_alot){
? ? ? ? ? ? // minor collection only
? ? ? ? ? ? collect(cause,0);
? ? ? ? }else{
? ? ? ? ? ? // Stop-the-world full
? ? ? ? ? ? collectioncollect(cause,n_gens()-1);
? ? ? ? }
? ? ?#else// Stop-the-world full
? ? ? ? collectioncollect(cause,n_gens()-1);
? ? ?#endif
? ?}
}
boolGenCollectedHeap::should_do_concurrent_full_gc(GCCause::Causecause){
? ?returnUseConcMarkSweepGC&&((cause==GCCause::_gc_locker&&GCLockerInvokesConcurrent)||(cause==GCCause::_java_lang_system_gc&&ExplicitGCInvokesConcurrent));
}
使用場(chǎng)景:
在使用堆外內(nèi)存的時(shí)候檀蹋,需要使用到System.gc。
1.在申請(qǐng)對(duì)外內(nèi)存的時(shí)候云芦,如果發(fā)現(xiàn)可以分配的堆外內(nèi)存不夠的時(shí)候俯逾,試圖通過(guò)gc去釋放堆外內(nèi)存。堆外內(nèi)存的大小限制和jvm參數(shù)-XX:MaxDirectMemorySize有關(guān)
2.使用完堆外內(nèi)存時(shí)舅逸,可以使用System.gc來(lái)嘗試釋放桌肴。也可以獲取DirectByteBuffer對(duì)象關(guān)聯(lián)的Cleaner來(lái)直接釋放。
gc和堆外內(nèi)存的關(guān)系:
首先在java層面和在堆外分配的這塊內(nèi)存關(guān)聯(lián)的只有與之關(guān)聯(lián)的DirectByteBuffer對(duì)象了琉历,它記錄了這塊內(nèi)存的地址以及大小坠七。
gc如何能通過(guò)操作DirectByteBuffer對(duì)象來(lái)間接操作對(duì)應(yīng)的堆外內(nèi)存?
DirectByteBuffer對(duì)象在創(chuàng)建的時(shí)候關(guān)聯(lián)了一個(gè)PhantomReference旗笔,說(shuō)到PhantomReference它其實(shí)主要是用來(lái)跟蹤對(duì)象何時(shí)被回收的彪置,它不能影響gc決策,但是gc過(guò)程中如果發(fā)現(xiàn)某個(gè)對(duì)象除了只有PhantomReference引用它之外蝇恶,并沒(méi)有其他的地方引用它了拳魁,那將會(huì)把這個(gè)引用放到j(luò)ava.lang.ref.Reference.pending隊(duì)列里,在gc完畢的時(shí)候通知ReferenceHandler這個(gè)守護(hù)線程去執(zhí)行一些后置處理撮弧,而DirectByteBuffer關(guān)聯(lián)的PhantomReference是PhantomReference的一個(gè)子類(lèi)潘懊,在最終的處理里會(huì)通過(guò)Unsafe的free接口來(lái)釋放DirectByteBuffer對(duì)應(yīng)的堆外內(nèi)存塊