java System.gc 说明

在没有任何jvm参数配置的情况下,默认System.gc会触发一次full gc。针对cms gc的情况下,默认其实执行的是serial gc。

通过配置-XX:+ExplicitGCInvokesConcurrent 来避免执行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));

}

使用场景:

在使用堆外内存的时候,需要使用到System.gc。

1.在申请对外内存的时候,如果发现可以分配的堆外内存不够的时候,试图通过gc去释放堆外内存。堆外内存的大小限制和jvm参数-XX:MaxDirectMemorySize有关

2.使用完堆外内存时,可以使用System.gc来尝试释放。也可以获取DirectByteBuffer对象关联的Cleaner来直接释放。

gc和堆外内存的关系:

首先在java层面和在堆外分配的这块内存关联的只有与之关联的DirectByteBuffer对象了,它记录了这块内存的地址以及大小。

gc如何能通过操作DirectByteBuffer对象来间接操作对应的堆外内存?

DirectByteBuffer对象在创建的时候关联了一个PhantomReference,说到PhantomReference它其实主要是用来跟踪对象何时被回收的,它不能影响gc决策,但是gc过程中如果发现某个对象除了只有PhantomReference引用它之外,并没有其他的地方引用它了,那将会把这个引用放到java.lang.ref.Reference.pending队列里,在gc完毕的时候通知ReferenceHandler这个守护线程去执行一些后置处理,而DirectByteBuffer关联的PhantomReference是PhantomReference的一个子类,在最终的处理里会通过Unsafe的free接口来释放DirectByteBuffer对应的堆外内存块

你可能感兴趣的:(java System.gc 说明)